SpringBoot2.x使用緩存註解操作Redis

爲了進一步簡化 Redis 的使用, Spring還提供了緩存註解,使用這些註解可以有效簡化編程過程。

緩存管理器和緩存的啓用

Spring 在使用緩存註解前,需要配置緩存管理器,緩存管理器將提供一些重要的信息,如緩存類型、超時時間等。 Spring 可以支持多種緩存的使用,因此它存在多種緩存處理器,並提供了緩存處理器的接口 CacheManager 和與之相關的類。
在這裏插入圖片描述
從圖中可以看到, Spring 可以支持多種緩存管理機制,而整合 Redis,主要就是以使用類 RedisCacheManager 爲主。 在 Spring Boot的 starter 機制中,允許我們通過配置文件生成緩存管理器。

緩存管理器配置

使用配置文件生成 Redis 緩存管理器

在項目的配置文件中加入如下配置

#配置redis緩存管理器
#緩存類型,在默認的情況下,spring會自動根據上下文檢索
spring.cache.type=redis
spring.cache.cache-names=redisCache,hashCache

配置參數解析

  • spring.cache.type
    spring.cache.type 配置的是緩存類型,這裏配置爲 Redis, Spring Boot 就會自動生成 RedisCacheManager 對象。
  • spring.cache.cache-names
    spring.cache.cache-names 配置的是緩存名稱,多個名稱可以使用逗號分隔,以便於緩存註解的引用。

最後爲了使用緩存管理器,需要在 Spring Boot 的配置文件中加入驅動緩存的註解@EnableCaching,這樣就可以驅動 Spring 緩存機制工作了。

啓用緩存機制

@SpringBootApplication
@EnableCaching
public class RedisCacheApplication {
    public static void main(String[] args) {
        SpringApplication.run(RedisCacheApplication.class, args);
    }
}

常用的緩存註解

@Cacheable

使用了此註解的方法會將返回值放到緩存數據庫中

參數解析
  • value
    指定一個配置文件中的緩存策略,如果沒有指定value,則使用默認的緩存策略。
  • key
    給存儲的值起個名稱,在查詢時如果緩存中有名稱相同的,那麼則直接從緩存中將數據返回。
@CacheEvict

清除緩存

參數解析
  • value
    清除指定的緩存策略的所有對象,如果沒有指定value,那麼使用默認的緩存策略。

Spring 緩存註解的使用

@Override
@Cacheable(value = "redisCache", key = "'redis_user_'+#userId")
public User findUserById(Long userId) {
    log.info("findUserById入參=" + userId);
    Optional<User> byId = this.userDao.findById(userId);
    return byId.get();
}

在這裏插入圖片描述

Key的生成策略

通過觀察上圖可以發現,採用此種配置,key的生成規則是#{cacheName}::#{key}。

更新數據庫中的數據
@Override
@Transactional
@CachePut(value = "redisCache", key = "'redis_user_'+#result.userId"
        , condition = "#result!='null'")
public User updateUser(User user) {
    log.info("updateUser入參=" + JSON.toJSONString(user));
    User userById = this.findUserById(user.getUserId());
    if (Objects.isNull(userById)){
        System.out.println("數據錯誤");
    }
    User save = this.userDao.save(user);
    return save;
}

在調用這個方法的時候,可以看到執行了查詢數據庫的操作,所以並沒有查緩存!
在這裏插入圖片描述
問題分析
更新數據,需要慎重一些。一般我們不能輕易地相信緩存,因爲緩存存在髒讀的可能性, 這是需要注意的,在需要更新數據時我們往往考慮先從數據庫查詢出最新數據,而後再進行操作。因此,這裏使用了 findUserById 方法,這裏會存在一個誤區,findUserById 方法存在註解@Cacheable,所以會從緩存中讀取數據,從而拿着緩存中的數據去更新數據庫的數據,這是一個非常危險的行爲!然而 通過上面的測試卻發現查的是數據庫的數據,也就是說@Cacheable 這個註解失效了!即使用 updateUser 方法調用 findUserById 方法,但是並不存在讀取緩存的可能,它每次都會執行 SQL 從數據庫中去查詢數據,而且這便是緩存註解自調用失效的問題。

緩存註解自調用失效問題

和數據庫事務的自調用失效原理一樣,因爲 Spring 的緩存機制也是基於 Spring AOP 實現的,而在 Spring 中 AOP 是通過動態代理技術來實現的,這裏的 updateUser方法調用 findUserById 方法是類內部的自調用, 並不存在代理對象的調用 ,這樣便不會出現 AOP,也就不會使用到標註在 findUserById 上的緩存註解,更不會去獲取其緩存的值了,這是需要注意的地方。也是我們在實際的工作和學習中我們需要注意這些問題。
AOP自調用失效演示案例:傳送門【該項目的AOP子模塊】

自定義緩存管理器

在 Spring Boot 中,如果採取上一種配置,則 RedisCacheManage中會採用永不超時的機制,如果我們並不希望採用 Spring Boot 機制帶來的鍵命名方式,也不希望緩存永不超時,這時我們可以自定義緩存管理器。畢竟永不超時的機制不利於數據的及時更新

重置 Redis 緩存管理器

修改配置文件的內容

#是否允許redis緩存空值
spring.cache.redis.cache-null-values=true
#redis的鍵前綴
spring.cache.redis.key-prefix=
#緩存超時時間戳,配置爲0則不設置超時時間
spring.cache.redis.time-to-live=6000ms
#是否啓用redis的鍵前綴
spring.cache.redis.use-key-prefix=false

在這裏插入圖片描述
可以觀察到,key的規則已經發生改變。
有時候,在重置 Redis 緩存管理器時可能存在比較多的配置, 也可以不採用 Spring Boot 自動配置的緩存管理器, 而是使用自定義的緩存管理器,這也是沒有問題的。首先需要刪除關於 Redis 緩存管理器的配置。然後給 IoC 容器增加緩存管理器。

自定義緩存管理器
@Autowired
private RedisConnectionFactory redisConnectionFactory;

/**
 * 自定義Redis緩存管理器
 *
 * @return
 */
@Bean(name = "redisCacheManager")
public RedisCacheManager iniRedisCacheManager() {
//        redis加鎖的寫入器
    RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(redisConnectionFactory);
//        啓用redis緩存的默認配置
    RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
//        設置JDK序列化器
    config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new JdkSerializationRedisSerializer()));
//        禁用前綴
    config = config.disableKeyPrefix();
//        設置超時時間10分鐘
    config.entryTtl(Duration.ofMinutes(10));
    RedisCacheManager redisCacheManager = new RedisCacheManager(writer, config);
    return redisCacheManager;
}

這裏首先注入了 RedisConnectionFactory 對象,該對象是由 Spring Boot 自動生成的。在創建 Redis 緩存管理器對象 RedisCacheManager 的時候,首先創建了帶鎖的 RedisCacheWriter 對象, 然後使用 RedisCacheConfiguration 對其屬性進行配置,這裏設置了禁用前綴,並且超時時間爲 10 min:最後就通過 RedisCacheWriter 對象和 RedisCacheConfiguration 對象去構建 RedisCacheManager 對象了,這樣 就完成了 Redis 緩存管理器的自定義。
項目案例

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章