1.springboot整合Redis作缓存(10)

(1)当Redis当做数据库或者消息队列来操作时,一般使用RedisTemplate来操作

(2)当Redis作为缓存使用时,可以将它作为Spring Cache的实现,直接通过注解使用

2.引入依赖:

(1)在pom文件中添加依赖:

      <!-- 配置测试依赖 -->
       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
       <!-- 配置redis依赖 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-pool2</artifactId>
		</dependency>

3.创建配置文件application.properties

(1)配置redis数据源

spring.redis.host=127.0.0.1
spring.redis.port=6379
#根据需要
#spring.redis.password=root 
# 连接超时时间(毫秒)
spring.redis.timeout=10000
# Redis默认情况下有16个分片,这里配置具体使用的分片,默认是0
spring.redis.database=0
# 连接池最大连接数(使用负值表示没有限制) 默认 8
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
spring.redis.lettuce.pool.max-wait=-1
# 连接池中的最大空闲连接 默认 8
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接 默认 0
spring.redis.lettuce.pool.min-idle=0

(2)SpringBoot将会自动配置redis,注入相关bean

(3)就可以使用@CacheConfig,@Cacheable,@CachePut,@CacheEvict了

4.使用Cache注解时的问题

(1)缓存对象集合中,缓存是以key-value形式保存的

(2)当不指定缓存的key时,SpringBoot会使用SimpleKeyGenerator生成key

  <1>它是使用方法参数组合生成的一个key

(3)SpringBoot会使用SimpleKeyGenerator生成key的缺点

  <1>如果2个方法,参数是一样的,但执行逻辑不同

  <2>那么将会导致执行第二个方法时命中第一个方法的缓存

(4)Spring同样提供了方案:继承CachingConfigurerSupport并重写keyGenerator()

   <1>下面贴出代码:


    @Configuration
    @EnableCaching//启用缓存
    public class RedisConfig extends CachingConfigurerSupport{
    /*
     *如果没有这个bean,则redis可视化工具中的中文内容都会以二进制存储,不易检查
     *项目启动时此方法先被注册成bean被spring管理
     *覆写替换系统默认redisTemplete
     */
       @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
      // 使用Jackson2JsonRedisSerialize 替换默认的jdkSerializeable序列化
     Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new    Jackson2JsonRedisSerializer(Object.class);
        //解决查询缓存转换异常的问题
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
 
        // 设置value的序列化规则和 key的序列化规则
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;}

 /**
     * 自定义生成key的规则
     * @return
     */
    @Override
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object o, Method method, Object... objects) {
                //格式化缓存key字符串
                StringBuilder sb = new StringBuilder();
                //追加类名
                sb.append(o.getClass().getName());
                //追加方法名
                sb.append(method.getName());
                //遍历参数并且追加
                for (Object obj : objects){sb.append(obj.toString());
                }System.out.println("调用Redis缓存Key : " + sb.toString());return sb.toString(); }};}

 /**
     * 采用RedisCacheManager作为缓存管理器
     * @param redisTemplate
     * @return
     */
     @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisTemplate) {
    	  return RedisCacheManager
                  .builder(redisTemplate)
                  .transactionAware()
                  .build();}}

   <2>缓存的key是包名+方法名+参数列表,这样就很难会冲突了

5.编写Redis操作工具类

(1)将RedisTemplate实例包装成一个工具类,便于对redis进行数据操作

(2)代码示例如下:

/**
 * redis操作工具类. (基于RedisTemplate)
 */
@Component
public class RedisUtils {
	@Autowired
	private RedisTemplate<String, String> redisTemplate;
	/**
	 * 读取缓存 
	 * @param key
	 * @return
	 */
	public String get(final String key) {
		return redisTemplate.opsForValue().get(key);}
	/**
	 * 写入缓存
	 */
	public boolean set(final String key, String value) {
		boolean result = false;
		try {redisTemplate.opsForValue().set(key, value);
			result = true;
		} catch (Exception e) {e.printStackTrace();}return result;}
	/**
	 * 更新缓存
	 */
	public boolean getAndSet(final String key, String value) {
		boolean result = false;
		try {redisTemplate.opsForValue().getAndSet(key, value);
			result = true;
		} catch (Exception e) {e.printStackTrace();}return result;}
	/**
	 * 删除缓存
	 */
	public boolean delete(final String key) {
		boolean result = false;
		try {redisTemplate.delete(key);result = true;
		} catch (Exception e) {e.printStackTrace();}return result;}}

6.测试类

(1)测试用例类来完成对redis的读写

(2)代码示例如下

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class RedisTest {
	@Resource
	private RedisUtils redisUtils;
	/**
	 * 插入缓存数据
	 */
	@Test
	public void set() {
		redisUtils.set("redis_key", "redis_vale");}
	/**
	 * 读取缓存数据
	 */
	@Test
	public void get() {
		String value = redisUtils.get("redis_key");
		System.out.println(value);}}

7.控制层调用redis

@RestController
@RequestMapping("/redis")
public class RedisController {
	// @Autowired
	// 系统默认的StringRedisTemplete
	// private StringRedisTemplate stringRedisTemplate;
	@Resource
	private RedisUtil redisUtil;
	// 添加
	@RequestMapping(value = "/add", method = RequestMethod.POST)
	public void saveRedis() {
		redisUtil.set("test-key2", "test-value");}
	// 获取
	@RequestMapping(value = "/get", method = RequestMethod.GET)
	public String getRedis() {
		return redisUtil.get("test-key2").toString();}}

8.springboot2.0集成Redis注意事项

(1)默认使用lettuce作为客户端

(2)在springboot2.0以下版本默认使用Jedis作为客户端

    <1>Jedis自带连接池,不需要添加依赖

    <2>lettuce没有连接池,如果想要使用连接池需要手动添加依赖并配置

    <3>springboot集成redis缓存有注解方式,redisAPI方式等

       3.1.注解方式简单

       3.2.redisAPI方式灵活