springboot集成redis缓存

  • springboot项目中,默认继承spring data redis ,spring data redis 针对redis提供了非常方便的操作模板类,redisTemplate 并可以进行连接池自动管理

    依赖导入

    1. <!-- spring boot redis缓存引入 -->
    2. <dependency>
    3. <groupId>org.springframework.boot</groupId>
    4. <artifactId>spring-boot-starter-data-redis</artifactId>
    5. </dependency>
    6. <!-- 缓存连接池-->
    7. <dependency>
    8. <groupId>org.apache.commons</groupId>
    9. <artifactId>commons-pool2</artifactId>
    10. </dependency>
    11. <!-- redis 存储 json序列化 -->
    12. <dependency>
    13. <groupId>com.fasterxml.jackson.core</groupId>
    14. <artifactId>jackson-databind</artifactId>
    15. </dependency>
    16. <dependency>
    17. <groupId>com.fasterxml.jackson.datatype</groupId>
    18. <artifactId>jackson-datatype-jsr310</artifactId>
    19. </dependency>

    配置

    #spring: 
    redis:
      host: xxxxx
      port: 6379
      database: 0
      password: 123456 #默认为空
      timeout: 3000ms #最大等待时间,超时则抛出异常,否则请求一直等待
      lettuce:
        pool:
          max-active: 20  #最大连接数,负值表示没有限制,默认8
          max-wait: -1    #最大阻塞等待时间,负值表示没限制,默认-1
          max-idle: 8     #最大空闲连接,默认8
          min-idle: 0     #最小空闲连接,默认0
    

    测试

    ```java package com.addicated.srb.core;

import com.addicated.srb.core.mapper.DictMapper; import com.addicated.srb.core.pojo.entity.Dict; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.test.context.junit4.SpringRunner;

import java.util.concurrent.TimeUnit; @SpringBootTest @RunWith(SpringRunner.class) public class RedisTest {

@Autowired
private RedisTemplate redisTemplate;


@Autowired
private DictMapper dictMapper;

@Test
public void saveDict(){
    Dict dict = dictMapper.selectById(1);
    redisTemplate.opsForValue().set("dict", dict, 5, TimeUnit.MINUTES);    }

}

<a name="LazmR"></a>
## 查看结果
![image.png](https://cdn.nlark.com/yuque/0/2021/png/1608527/1633674396562-e5999549-dd10-4ba6-a9a4-726a6284bdb0.png#clientId=ud2d49845-0327-4&from=paste&height=136&id=u017f80fa&margin=%5Bobject%20Object%5D&name=image.png&originHeight=271&originWidth=940&originalType=binary&ratio=1&size=72815&status=done&style=none&taskId=udd8e169b-a228-4387-9a20-9f65b640fb8&width=470)

- 如上图,会发现肉眼不可识别,这则是redisTemplate默认使用了jdk序列化方式存储了kv
- 于是我们要自行对redistTemplate进行配置,方便我们的使用
<a name="STNDC"></a>
## 添加配置类
```java
package com.addicated.srb.base.config;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;


@Configuration
public class RedisConfig {


    @Bean
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory) {

        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();

        // 设定连接池信息
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        // 首先解决key的序列化方式
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringRedisSerializer);

        // 解决value 的序列化方式
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);

        // 序列化时讲类的数据类型存入json 以便翻序列化的时候转换成正确的类型
        ObjectMapper objectMapper = new ObjectMapper();
        //objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);

        // 解决jackson2无法反序列化LocalDateTime的问题
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.registerModule(new JavaTimeModule());


        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        return redisTemplate;

    }

}

再次进行测试

image.png

  • 可以看到已经是可读的状态

    redis用做缓存

  @Override
    public List<Dict> listByParentId(Long parentId) {
        //先查询redis中是否存在数据列表
        List<Dict> dictList = null;
        try {
            dictList = (List<Dict>) redisTemplate.opsForValue().get("srb:core:dictList:" + parentId);
            if (dictList != null) {
                log.info("从redis中取值");
                return dictList;
            }
        } catch (Exception e) {
            log.error("redis服务器异常:" + ExceptionUtils.getStackTrace(e));//此处不抛出异常,继续执行后面的代码
        }

        log.info("从数据库中取值");
        dictList = baseMapper.selectList(new QueryWrapper<Dict>().eq("parent_id", parentId));
        dictList.forEach(dict -> {
            //如果有子节点,则是非叶子节点
            boolean hasChildren = this.hasChildren(dict.getId());
            dict.setHasChildren(hasChildren);
        });
        //将数据存入redis
        try {
            redisTemplate.opsForValue().set("srb:core:dictList:" + parentId, dictList, 5, TimeUnit.MINUTES);
            log.info("数据存入redis");
        } catch (Exception e) {
            log.error("redis服务器异常:" + ExceptionUtils.getStackTrace(e));//此处不抛出异常,继续执行后面的代码
        }
        return dictList;


    }