java中使用redis
redis 客戶端操作工具:
Jedis api 在線網址:http://tool.oschina.net/uploads/apidocs/redis/clients/jedis/Jedis.html
redisson 官網地址:https://redisson.org/
redisson git項目地址:https://github.com/redisson/redisson
lettuce 官網地址:https://lettuce.io/
lettuce git項目地址:https://github.com/lettuce-io/lettuce-core
概念:
Jedis:是Redis的Java實現客戶端,提供了比較全面的Redis命令的支持,
Redisson:實現了分布式和可擴展的Java數據結構。
Lettuce:高級Redis客戶端,用於線程安全同步,異步和響應使用,支持集群,Sentinel,管道和編碼器。
優點:
Jedis:比較全面的提供了Redis的操作特性
Redisson:促使使用者對Redis的關注分離,提供很多分布式相關操作服務,例如,分布式鎖,分布式集合,可通過Redis支持延遲隊列
Lettuce:主要在一些分布式緩存框架上使用比較多
可伸縮:
Jedis:使用阻塞的I/O,且其方法調用都是同步的,程序流需要等到sockets處理完I/O才能執行,不支持異步。Jedis客戶端實例不是線程安全的,所以需要通過連接池來使用Jedis。
Redisson:基於Netty框架的事件驅動的通信層,其方法調用是異步的。Redisson的API是線程安全的,所以可以操作單個Redisson連接來完成各種操作
Lettuce:基於Netty框架的事件驅動的通信層,其方法調用是異步的。Lettuce的API是線程安全的,所以可以操作單個Lettuce連接來完成各種操作
1 maven依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <!--<version>2.1.4.RELEASE</version>--> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.68</version>
</dependency>
2、yml:
spring: redis: database: 0 # Redis數據庫索引(默認為0) host: 192.168.0.110 # Redis服務器地址 port: 6379 # Redis服務器連接端口 password: 123456 # Redis服務器連接密碼(默認為空) timeout: 5000ms # 連接超時時間(毫秒)默認是2000ms lettuce: pool: max-active: 200 # 連接池最大連接數(使用負值表示沒有限制) max-idle: 20 # 連接池中的最大空閑連接 min-idle: 0 # 連接池中的最小空閑連接 max-wait: -1ms # 連接池最大阻塞等待時間(使用負值表示沒有限制) #sentinel: #master: mymaster #哨兵監聽的master名稱 #nodes: 192.168.203.205:26479, 192.168.203.205:26480 #哨兵地址列表,多個以,分割 # cluster: # max-redirects: 3 # nodes: 192.168.0.201:7001,192.168.0.201:7002,192.168.0.201:7003,192.168.0.201:7004,192.168.0.201:7005,192.168.0.201:7006
配置RestTemplate 的序列化方式,默認使用jdk提供的序列化方式,不可讀,配置自己的序列化方式 :
@Configuration @EnableCaching //支持緩存注解 public class MyRedisConfig extends CachingConfigurerSupport { @Bean public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setKeySerializer(new StringRedisSerializer()); // key序列化 redisTemplate.setValueSerializer(new FastJsonRedisSerializer<>(Object.class)); // value序列化 redisTemplate.setHashKeySerializer(new StringRedisSerializer()); // Hash key序列化 redisTemplate.setHashValueSerializer(new StringRedisSerializer()); // Hash value序列化 redisTemplate.setConnectionFactory(redisConnectionFactory); return redisTemplate; } }
RedisTemplate操作Redis Api 請參考: https://www.cnblogs.com/dw3306/p/12840012.html
springboot + spring cache + redis 實現緩存
spring cache 是spring3版本之后引入的一項技術,可以簡化對於緩存層的操作,spring cache與springcloud stream類似,都是基於抽象層,可以任意切換其實現。其核心是CacheManager
、Cache
這兩個接口,所有由spring整合的cache都要實現這兩個接口、Redis的實現類則是 RedisCache
和 RedisManager。
1. 首先認識幾個用到的名稱及注解
@EnableCaching | 開啟基於注解的緩存,寫在啟動類上,這個注解會被spring發現,並且會創建一個切面(aspect) 並觸發Spring緩存注解的切點(pointcut) 。 根據所使用的注解以及緩存的狀態, 這個切面會從緩存中獲取數據, 將數據添加到緩存之中或者從緩存中移除某個值。 |
@Cacheable | 標注在方法上,如果該方法結果存在緩存則使用緩存,否則執行方法並將結果緩存 |
@CacheEvict | 清除緩存 |
@CachePut | 不管有沒有緩存都要執行方法,且把結果緩存,如果存在緩存就更新 |
Cache | 緩存接口,定義緩存操作 |
CacheManager | 緩存管理器,管理各種緩存組件 |
keyGenerator | 緩存數據時key的生成策略 |
serialize | 緩存數據時,value的序列化策略 |
當然,緩存管理器除了RedisCacheManager還有一些其他的。例如
- SimpleCacheManager
- NoOpCacheManager
- ConcurrentMapCacheManager
- CompositeCacheManager
- EhCacheCacheManager
默認緩存管理器:ConcurrentMapCacheManager,這個簡單的緩存管理器使用java.util.concurrent.ConcurrentHashMap作為其緩存存儲
@Cacheable屬性講解
@Cacheable 是一個既可以應用於方法級別,也可用於類級別的注解。自spring3.1開始就通過它實現了緩存管理。
@Cacheable
能干什么?
為了通俗易懂的理解,舉個栗子:一個方法,
getBooksByUsernameAndLanguage(String username, int language)
,顯然,是一個獲取數據庫里所有我的英文書對象的方法,返回應該是一個列表。如果這個函數的返回值很大,而且會在頁面上被經常調用,那么每一次調用都要重新連接數據庫並返回一個數據量龐大的list,可能頁面響應和資源占用會比較大。而我們希望的是,第一次調用這個方法時,返回的數據能被放到服務器端的緩存里,以便於后面要調用這個方法時,能直接從緩存里取到,這樣就不用再查數據庫占用資源了。而@Cacheable
的作用就是這個。
@Cacheable
怎么用?
@Cacheable(value = "CACHE_BOOK",key = "#username", condition = "#language = 1") public List<Book> getBooksByUsernameAndLanguage(String username, int language) { // balabalabala...里面的代碼不重要 return bookList; }
- value : 必須要的。就是個自己取的名字,通過它指明了第一次調用這個方法時返回的bookList將被存在內存的哪里。
- key : 可選。要使用SpEL表達式,這里與參數
username
對應,當傳入的username值變了的話就不去取緩存里的數據了,而是執行getBooksByUsernameAndLanguage
方法。(這是必須的,因為username變了,返回值也就變了,緩存里的數據不符合了,因此這個選項很重要)。spring默認用方法的簽名來當做key。 - condition:方法返回的結果bookList,要不要緩存起來?condition就添加了一個限定條件。這個例子中,只有傳入的語言代碼是1,返回的bookList才會被緩存起來,如果給language傳了別的值,那么bookList是不會緩存起來的。
參數名 | 作用 |
---|---|
cacheNames | 被緩存的時候的命名空間 |
key | 這里的key的優先級是最高的,可以覆蓋掉全局配置的key,如果不配置的話使用的就是全局的key |
keyGenerator | 指定的緩存的key的生成器,默認沒有 |
cacheManager | 指定要使用哪個緩存管理器。默認是底層自動配置的管理器 |
condition | 滿足什么條件會進行緩存,里面可以寫簡單的表達式進行邏輯判斷 |
unless | 滿足什么條件不進行緩存,里面可以寫簡單的表達式進行邏輯判斷 |
sync | 加入緩存的這個操作是否是同步的 |
value |
指定將方法的返回結果放在哪個緩存中,可以指定多個,用大括號保存 |
@CacheEvict簡單屬性講解
參數名 | 描述 |
---|---|
allEntries | 是否刪除該命名空間下面的全部緩存,默認是false |
beforeInvocation | 在執行刪除方法前就執行清空緩存操作,默認是false,如果刪除方法執行報錯該注解則不執行 |
@CacheConfig簡化注解配置
標注在類上,類中方法就不需要再指定該注解說配置好的屬性
參數名 | 參數值 | 作用 |
---|---|---|
cacheNames | 可以隨意填寫,一般是一個模塊或者一個很重要的功能名稱 | 無具體作用,只是用來區分緩存,方便管理 |
keyGenerator | 就是自己配置的KeyGenerator的名稱 | 全局key都會以他的策略去生成 |
cacheManager | 自己配置的CacheManager | 用來操作Cache對象的,很多對於緩存的配置也由他去管理 |
eg:
@Cacheable(key = "#id", unless = "#result == null") @PatchMapping("/course/{id}") public Course courseInfo(@PathVariable Integer id) { log.info("進來了 .. "); return courseService.getCourseInfo(id); }
#result是代表函數的返回值
cache 配置:
在上面的 MyRedisConfig 中添加如下配置:
/** * key的生成策略的配置: 類名+方法名+參數列表的類型+參數值 再做 哈希散列 作為key * * @return */ @Bean @Override public KeyGenerator keyGenerator() { log.info("RedisCacheConfig.keyGenerator()"); return new KeyGenerator() { @Override public Object generate(Object o, Method method, Object... objects) { StringBuilder sb = new StringBuilder(); sb.append(o.getClass().getSimpleName()) .append(":") .append(method.getName()) .append(":"); for (Object obj : objects) { if (null != obj) {// 替換字符串 String objKey = JSON.toJSONString(obj); objKey = objKey.replace(":", "="); sb.append(objKey); } } return sb.toString(); } }; } //緩存生存時間 private Duration timeToLive = Duration.ofHours(1); @Bean public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) { //redis緩存配置 RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() //緩存生存時間 .entryTtl(this.timeToLive) // 配置序列化(解決亂碼的問題) .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer())) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new FastJsonRedisSerializer<>(Object.class))) // 不緩存空值 .disableCachingNullValues(); //根據redis緩存配置和reid連接工廠生成redis緩存管理器 RedisCacheManager redisCacheManager = RedisCacheManager.builder(connectionFactory) .cacheDefaults(config) .build(); log.debug("自定義RedisCacheManager加載完成"); return redisCacheManager; } private RedisSerializer<String> keySerializer() { return new StringRedisSerializer(); }
啟動類上添加: @EnableCaching //支持緩存注解