首頁  >  文章  >  資料庫  >  Redis快取實例程式碼分析

Redis快取實例程式碼分析

王林
王林轉載
2023-06-03 20:37:561453瀏覽

一、簡介

1、場景

由於資料字典的變化不是很頻繁,而且系統對資料字典的存取較頻繁,所以我們有必要把資料字典的資料存入緩存,減少資料庫壓力和提高存取速度。這裡,我們使用Redis作為系統的分散式快取中間件。

2、RedisTemplate

在Spring Boot專案中,預設整合Spring Data Redis,Spring Data Redis針對Redis提供了非常方便的操作模版RedisTemplate,並且可以進行連接池自動管理。

二、引入Redis

1、專案中整合Redis

service-base模組中加入redis依賴,Spring Boot 2.0以上預設透過commons-pool2連線池連接Redis

<!-- spring boot 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>
<!-- redis 存储 json序列化 -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
</dependency>

2、新增Redis連線設定

service-core的application.yml 中新增以下設定

#spring: 
  redis:
。 #    lettuce:
      pool:
        max-active: 20  #最大連結數,負值表示沒有限制,預設8
        max-wait: -1  等待限制#p        max-wait: -1  等待值預設-1
        max-idle: 8     #最大閒置連接,預設為8
        min-idle: 0     #最小閒置連接,預設0

Red#S##Red#Red#S##Red#S#Red#S#Red#如果服務服務服務#3、啟動服務服務。
遠端連接Linux伺服器,這裡本機使用centos虛擬機器上的redis

##啟動服務
cd /usr/local/redis-5.0.7

bin/redis- server redis.conf

三、測試RedisTemplate

1、存值測試

test中建立測試類別RedisTemplateTests

@SpringBootTest
@RunWith(SpringRunner.class)
public class RedisTemplateTests {
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private DictMapper dictMapper;
    @Test
    public void saveDict(){
        Dict dict = dictMapper.selectById(1);
        //向数据库中存储string类型的键值对, 过期时间5分钟
        redisTemplate.opsForValue().set("dict", dict, 5, TimeUnit.MINUTES);
    }
}
發現RedisTemplate默認使用了JDK的序列化方式儲存了key和value,可讀性差

#2、Redis設定檔

service-base中加入RedisConfig,我們可以在這個設定檔中配置Redis序列化方案

@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;
    }
}

再次測試,key使用了字串存儲,value使用了json存儲Redis快取實例程式碼分析

##3、取值測試

@Test
public void getDict(){
    Dict dict = (Dict)redisTemplate.opsForValue().get("dict");
    System.out.println(dict);
}

四、將資料字典存入redis

DictServiceImpl

Redis快取實例程式碼分析注意:當redis伺服器宕機時,我們不要拋出異常,要正常的執行後面的流程,使業務可以正常的運行

@Resource
private RedisTemplate redisTemplate;
@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;
}

集成redis總結:

(1)導入相關依賴;

(2)配置redis連接資訊;

(3)測試連接,取值測試,存值測試;

(4)依照自己的需求配置序列化器,否則預設使用jdk的序列化器。

redis業務總結:

(1)首先查詢redis中有無對應的快取信息,有的話取出直接返回,沒有執行(2),如果redis因為某種原因連接不上例如宕機,此時列印錯誤日誌,繼續查詢資料庫;

(2)沒有的話查詢資料庫,將資料存放進redis並回傳資料。

以上是Redis快取實例程式碼分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除