1. 程式人生 > >Spring Boot 8:Redis使用

Spring Boot 8:Redis使用

Redis有兩個模板:RedisTemplate 和 StringRedisTemplate。不推薦使用 RedisTemplate,因為 RedisTemplate 提供的是操作物件,而我們通常以 JSON 格式儲存該物件,儲存時會使用 Redis 預設的內部序列化器,容易導致儲存內容出現亂碼。此時需要我們自定義序列化。
StringRedisTemplate 為我們提供了字串操作,將實體類轉換成 JSON 字串進行儲存,等取出來後,再將其轉換成相應的物件

pom.xml

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

application.yml

spring
  redis:
    #        open: false  # 是否開啟redis快取  true開啟   false關閉
    database: 0
    host: 127.0.0.1
    port: 6379
    password:
    timeout: 6000  # 連線超時時長(毫秒)
    pool:
      max-active: 1000  # 連線池最大連線數(使用負值表示沒有限制)
      max-wait: -1      # 連線池最大阻塞等待時間(使用負值表示沒有限制)
      max
-idle: 10 # 連線池中的最大空閒連線 min-idle: 5 # 連線池中的最小空閒連線

RedisConfig

使用StringRedisTemplate可以不重寫keyGenerator方法

/**
 * Redis 配置
 *
 * @Author YangXuyue
 * @Date 2018/08/02 21:57
 */
@Configuration
@EnableCaching
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisConfig extends
CachingConfigurerSupport { /* 快取命中率 即從快取中讀取資料的次數 與 總讀取次數的比率,命中率越高越好: 命中率 = 從快取中讀取次數 / (總讀取次數[從快取中讀取次數 + 從慢速裝置上讀取的次數]) Miss率 = 沒有從快取中讀取的次數 / (總讀取次數[從快取中讀取次數 + 從慢速裝置上讀取的次數]) 這是一個非常重要的監控指標,如果做快取一定要健康這個指標來看快取是否工作良好 */ /* 快取策略 Eviction policy 移除策略,即如果快取滿了,從快取中移除資料的策略;常見的有LFU、LRU、FIFO: FIFO(First In First Out):先進先出演算法,即先放入快取的先被移除; LRU(Least Recently Used):最久未使用演算法,使用時間距離現在最久的那個被移除; LFU(Least Frequently Used):最近最少使用演算法,一定時間段內使用次數(頻率)最少的那個被移除; TTL(Time To Live ) 存活期,即從快取中建立時間點開始直到它到期的一個時間段(不管在這個時間段內有沒有訪問都將過期) TTI(Time To Idle) 空閒期,即一個數據多久沒被訪問將從快取中移除的時間 */ /* Spring提供了Cache:org.springframework.cache;該Cache提供了快取操作的讀取/寫入/移除方法 因為應用並不是只有一個Cache,所以Spring提供了CacheManager抽象,用於快取管理 Cache和CacheManager都有其預設實現(GuavaXXX,EhCacheXXX...) GuavaCacheManager之外,其他Cache都支援Spring事務的,即如果事務回滾了,Cache的資料也會移除掉。 */ /* 繼承CachingConfigurerSupport,實現後注入需要的cacheManager和keyGenerator */ // 設定RedisCacheManager。在配置 CacheManager 的方法中,也可以配置快取預設的過期時間。 @Bean public CacheManager cacheManager(RedisTemplate redisTemplate) { RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate); // 設定快取過期時間,單位秒 Map<String, Long> expiresMap = new HashMap<>(); expiresMap.put(CacheNames.MASTER, 600L); expiresMap.put(CacheNames.SECOND, 600L); // 設定超時 cacheManager.setExpires(expiresMap); // TODO 沒有設定的快取預設過期時間 //cacheManager.setDefaultExpiration(60 * 60L); return cacheManager; } @Bean public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) { StringRedisTemplate template = new StringRedisTemplate(factory); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); template.setValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } /** * Redis 設定一些全域性配置,比如配置主鍵的生產策略 KeyGenerator,如不配置會預設使用引數名作為主鍵。 * * @return */ @Override @Bean public KeyGenerator keyGenerator() { return new BaseKeyGenerator(); } /** * Redis主鍵生成策略 */ private class BaseKeyGenerator implements KeyGenerator { @Override public Object generate(Object target, Method method, Object... params) { // 目標Object的名稱+方法名+Params各個元素名稱 StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getSimpleName()); sb.append(".").append(method.getName()); for (Object obj : params) { if (null != obj) { sb.append(obj.toString()); } } return sb.toString(); } } }

註解使用例子

@Service
@CacheConfig(cacheNames = {CacheNames.MASTER})
public class UserServiceImpl implements UserService {
    /*
    @CacheConfig:主要用於配置該類中會用到的一些共用的快取配置。在這裡@CacheConfig(cacheNames = {CacheNames.MASTER}):
    配置了該資料訪問物件中返回的內容將儲存於名為users的快取物件中,我們也可以不使用該註解,直接通過@Cacheable自己配置快取集的名字來定義。
     */

    @Autowired
    private UserRepository repository;

    /*
    儲存的值為返回值,註解方面再研究研究。合理使用快取的key,不然會沒有效果
     */

    /*
    @CachePut效果與@Cacheable一樣
    因為@CachePut是方法執行完才生效,所以當新增一個user的時候,user的id是有值的

    這裡只針對user的id做了user的快取,如果findByUsername也做快取,那麼資料將會出現不一致的情況
    因為key值不一樣,會更新不到以username為key資訊的快取
     */

    /*
    快取註解詳解

    @Cacheable:配置了findByName函式的返回值將被加入快取。同時在查詢時,會先從快取中獲取,若不存在才再發起對資料庫的訪問。該註解主要有下面幾個引數:
        value、cacheNames:兩個等同的引數(cacheNames為Spring 4新增,作為value的別名),
            用於指定快取儲存的集合名。由於Spring 4中新增了@CacheConfig,因此在Spring 3中原本必須有的value屬性,也成為非必需項了
        key:快取物件儲存在Map集合中的key值,非必需,預設按照函式的所有引數組合作為key值,若自己配置需使用SpEL表示式,比如:@Cacheable(key = "#p0"):
            使用函式第一個引數作為快取的key值,更多關於SpEL表示式的詳細內容可參考官方文件
        condition:快取物件的條件,非必需,也需使用SpEL表示式,只有滿足表示式條件的內容才會被快取,
             比如:@Cacheable(key = "#p0", condition = "#p0.length() < 3"),表示只有當第一個引數的長度小於3的時候才會被快取,
             若做此配置上面的AAA使用者就不會被快取,讀者可自行實驗嘗試。
        unless:另外一個快取條件引數,非必需,需使用SpEL表示式。它不同於condition引數的地方在於它的判斷時機,
            該條件是在函式被呼叫之後才做判斷的,所以它可以通過對result進行判斷。
        keyGenerator:用於指定key生成器,非必需。若需要指定一個自定義的key生成器,
            我們需要去實現org.springframework.cache.interceptor.KeyGenerator介面,並使用該引數來指定。需要注意的是:該引數與key是互斥的
        cacheManager:用於指定使用哪個快取管理器,非必需。只有當有多個時才需要使用
        cacheResolver:用於指定使用那個快取解析器,非必需。需通過org.springframework.cache.interceptor.CacheResolver介面來實現自己的快取解析器,並用該引數指定。
    @CachePut:配置於函式上,能夠根據引數定義條件來進行快取,它與@Cacheable不同的是,它每次都會真是呼叫函式,所以主要用於資料新增和修改操作上。
        它的引數與@Cacheable類似,具體功能可參考上面對@Cacheable引數的解析
    @CacheEvict:配置於函式上,通常用在刪除方法上,用來從快取中移除相應資料。除了同@Cacheable一樣的引數之外,它還有下面兩個引數:
        allEntries:非必需,預設為false。當為true時,會移除所有資料
        beforeInvocation:非必需,預設為false,會在呼叫方法之後移除資料。當為true時,會在呼叫方法之前移除資料。
     */

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CachePut(key = "'UserService_UserId_'+#user.id")
    public User save(User user) {
        return repository.save(user);
    }

    @Override
    @Cacheable(key = "'UserService_UserId_'+#id")
    public User findById(Long id) {
        return repository.findById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(key = "'UserService_UserId_'+#id")
    public void deleteById(Long id) {
        repository.delete(id);
    }

}
public interface CacheNames {
    /**
     * 主快取名稱
     */
    String MASTER = "master";

    String SECOND = "second";

}