SpringBoot3集成Redis的方法詳解
一、簡介
緩存在項目開發(fā)中,基本上是必選組件之一,Redis作為一個key-value
存儲系統(tǒng),具備極高的數據讀寫效率,并且支持的數據類型比較豐富,在業(yè)務場景中的應用非常廣泛;
Redis典型的應用場景就是數據緩存能力,用來解決業(yè)務中最容易出現的查詢性能問題,提升系統(tǒng)的響應效率;其次就是分布式鎖機制,用來解決分布式系統(tǒng)中多線程并發(fā)處理資源的安全問題;
二、工程搭建
1、工程結構
2、依賴管理
Redis的客戶端使用的是lettuce
組件的6.2.4.RELEASE
版本,該組件具備可擴展和線程安全的特性,支持Redis各種高級功能,如哨兵,集群,流水線,自動重新連接等;
<!-- Redis組件 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>${spring-boot.version}</version> </dependency> <!-- Spring集成Redis組件 --> <dependency> <groupId>org.springframework.integration</groupId> <artifactId>spring-integration-redis</artifactId> <version>${spring-integration.version}</version> </dependency>
3、Redis配置
配置文件,在lettuce
組件中默認使用的是common-pool2
連接池組件,在配置中定義幾個常用的核心參數;
spring: # Redis配置 data: redis: host: 127.0.0.1 port: 6379 database: 1 # 讀超時 timeout: 3000 # 連接超時 connectTimeout: 5000 # Lettuce連接池 lettuce: pool: # 最小空閑連接 min-idle: 5 # 最大空閑連接 max-idle: 10 # 最大連接數 max-active: 100 # 連接分配應該阻塞的最大時間 max-wait: 2000
配置類
@Configuration public class RedisConfig { /** * RedisTemplate模板 */ @Bean("redisTemplate") public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(factory); redisTemplate.setKeySerializer(new StringRedisSerializer()); return redisTemplate; } /** * StringRedisTemplate模板 */ @Bean public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) { StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(); stringRedisTemplate.setConnectionFactory(factory); stringRedisTemplate.setKeySerializer(new StringRedisSerializer()); return stringRedisTemplate; } /** * Redis分布式鎖 */ @Bean public RedisLockRegistry redisLockRegistry(RedisConnectionFactory factory){ // 1、鎖的密鑰前綴:REDIS-LOCK // 2、鎖的過期時間:20秒 return new RedisLockRegistry(factory, "REDIS-LOCK",20000L); } }
三、Redis用法
1、環(huán)境搭建
Redis文檔中推薦使用brew
工具安裝的方式,本地環(huán)境中是4.1
版本,可以搜索到redis@6.2
,即安裝該版本,并且可以使用brew
命令管理Redis的啟動和停止;
brew --version Homebrew 4.1.0 brew search redis ==> Formulae redis redis-leveldb redis@3.2 redis@4.0 redis@6.2 brew install redis@6.2 brew services start redis@6.2 ==> Successfully started `redis@6.2` (label: homebrew.mxcl.redis@6.2) brew services restart redis@6.2 ==> Successfully stopped `redis@6.2` (label: homebrew.mxcl.redis@6.2) ==> Successfully started `redis@6.2` (label: homebrew.mxcl.redis@6.2) brew services stop redis@6.2 ==> Successfully stopped `redis@6.2` (label: homebrew.mxcl.redis@6.2)
配置Redis環(huán)境變量,這樣可以在命令行使用Redis原生的指令進行啟動和客戶端操作,在測試完成之后,Mac系統(tǒng)本地的redis@6.2
環(huán)境就配置好了;
open -e ~/.bash_profile export REDIS_HOME=/usr/local/opt/redis@6.2 export PATH=$REDIS_HOME/bin:$PATH source ~/.bash_profile redis-server Redis 6.2.13 ,Running in standalone mode , Port: 6379 , PID: 7966 redis-cli 127.0.0.1:6379> select 1 OK 127.0.0.1:6379> set redis-key redis-value OK 127.0.0.1:6379> get redis-key "redis-value" 127.0.0.1:6379> del redis-key (integer) 1
2、數據類型
Strings:字符串是最基本的數據類型,表示一個字節(jié)序列,也是最常使用的類型,單個最大能夠存儲512MB
;
public void dataString () throws Exception { // 1、添加K-V緩存 redisTemplate.opsForValue().set("key-01","value-01",300, TimeUnit.SECONDS); // 2、添加JSON格式 JsonMapper jsonMapper = new JsonMapper() ; String jsonVar = jsonMapper.writeValueAsString(new IdValue(1,"Json格式")) ; redisTemplate.opsForValue().set("key-02",jsonVar,500,TimeUnit.SECONDS); Object key01 = redisTemplate.opsForValue().get("key-01"); Object key02 = redisTemplate.opsForValue().get("key-02"); log.info("key01:{},key02:{}",key01,key02); }
Lists:鏈表結構,可以有序的存儲多個字符串值,基于數據左寫入右讀取的方式可以模擬消息隊列,單個最大長度為2^32-1
;
public void dataList (){ // 1、左側寫數據 redisTemplate.opsForList().leftPushAll("data-list","value-01","value-02","value-03"); // 2、右側讀數據 Object rightPop01 = redisTemplate.opsForList().rightPop("data-list") ; Object rightPop02 = redisTemplate.opsForList().rightPop("data-list") ; log.info("rightPop01:{},rightPop02:{}",rightPop01,rightPop02); }
Sets:用來存儲無序的、唯一的字符串集合,通常用來跟蹤分析唯一項的業(yè)務場景,比如唯一標簽下的用戶群,獨立IP等;
public void dataSet (){ // 1、寫數據 redisTemplate.opsForSet().add("data-set","Java","C++","Python","C++"); // 2、讀數據 Object pop01 = redisTemplate.opsForSet().pop("data-set"); Object pop02 = redisTemplate.opsForSet().pop("data-set"); log.info("pop01:{},pop02:{}",pop01,pop02); }
Hashes:Redis本身的K-V
結構上,在value中可以再次使用K-V
數據類型,在涉及大規(guī)模的關系型數據存儲時,會優(yōu)先使用該類型;
public void dataHash (){ // 1、寫數據 HashMap<String,String> hashMap = new HashMap<>() ; hashMap.put("key1","value1") ; hashMap.put("key2","value2") ; redisTemplate.opsForHash().putAll("data-hash",hashMap); // 2、讀數據 Object kv1 = redisTemplate.opsForHash().get("data-hash","key1"); Object kv2 = redisTemplate.opsForHash().get("data-hash","key2"); log.info("kv1:{},kv2:{}",kv1,kv2); }
Sorted-sets:唯一的字符串集合,但是可以通過每個字符串的相關分數來維持順序,這里的分數可以表示排行順序,也可以標識為對象的權重或優(yōu)先級;
public void dataSortedSet (){ // 1、寫數據 redisTemplate.opsForZSet().add("sorted-set","Java",1.0); redisTemplate.opsForZSet().add("sorted-set","Python",3.0); redisTemplate.opsForZSet().add("sorted-set","C++",2.0); // 2、讀數據 Object popMax = redisTemplate.opsForZSet().popMax("sorted-set"); Object popMin = redisTemplate.opsForZSet().popMin("sorted-set"); log.info("popMax:{},popMin:{}",popMax,popMin); }
3、加鎖機制
使用SETNX
方法即代碼中的setIfAbsent
,如果key不存在,則設置key保存字符串的值,也就相當于SET,當key已經存在時,不執(zhí)行任何操作;
@Service public class RedisLockService { @Resource private RedisTemplate<String,Object> redisTemplate ; public Boolean lock (String lock,long timeout){ return redisTemplate.opsForValue().setIfAbsent(lock,lock,timeout, TimeUnit.SECONDS); } public void unLock (String lock){ Object lockVal = redisTemplate.opsForValue().get(lock); if (!Objects.isNull(lockVal) && Objects.equals(lockVal.toString(),lock)){ redisTemplate.delete(lock) ; } } }
RedisLockRegistry
是由spring-integration
組件提供的封裝類,基于Redis實現分布式鎖的能力;有關于兩種鎖機制的測試,可以查看代碼工程中RedisLockTest
單元測試類,
@Service public class LockRegistryService { @Resource protected RedisLockRegistry redisLockRegistry; /** * 嘗試一次加鎖 */ @SneakyThrows public <T> Boolean tryLock(T lockKey, Long time) { return redisLockRegistry.obtain(lockKey).tryLock(time, TimeUnit.SECONDS); } /** * 重試機制多次加鎖 */ @SneakyThrows public <T> Boolean reTryLock(T lockKey, Long time,int retryNum) { Boolean lockFlag = tryLock(lockKey, time); if (Boolean.TRUE.equals(lockFlag)) { return Boolean.TRUE; } for (int i = 0; i < retryNum; i++) { if (Boolean.TRUE.equals(tryLock(lockKey, time))){ return Boolean.TRUE; } } return Boolean.FALSE; } /** * 釋放鎖 */ public <T> void unlock(T lockKey) { redisLockRegistry.obtain(lockKey).unlock(); } }
四、Mybatis緩存
1、基礎配置
在Mybatis框架中,一級緩存是指SqlSession
級別內;二級緩存是指Mapper
級別內,需要在配置文件中開啟,二級緩存并不適用于頻繁修改數據的業(yè)務場景;
配置文件
mybatis-plus: configuration: cache-enabled: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
Mapper注解,這里使用自定義的MybatisCache
類,并且使用Redis組件來緩存數據;
@CacheNamespace(implementation = MybatisCache.class) public interface ArticleMapper extends BaseMapper<Article> { }
2、自定義實現
通過實現Cache
接口,來定義二級緩存的處理策略,可以運行MybatisTest
測試類中的方法,分析其執(zhí)行的原理,符合Cache-Aside
模式,即先查詢緩存,如果未命中就查詢數據庫,并將結果寫入緩存,數據更新時會刪除相關緩存;
public class MybatisCache implements Cache { private static final Logger log = LoggerFactory.getLogger(MybatisCache.class); private RedisTemplate<String,Object> redisTemplate ; private String id ; public MybatisCache (String id){ log.info("mybatis...cache...id:{}",id); this.id = id ; } public RedisTemplate<String,Object> getRedisTemplate(){ if(redisTemplate == null) { synchronized (MybatisCache.class) { if(redisTemplate == null) { redisTemplate = SpringContextUtil.getBean("redisTemplate",RedisTemplate.class); return redisTemplate; } return redisTemplate; } } return redisTemplate ; } @Override public String getId() { return this.id ; } @Override public void putObject(Object key, Object value) { log.info("mybatis...cache...put...key:{},value:{}",key,value); this.getRedisTemplate().opsForValue().set(String.valueOf(key),value,5, TimeUnit.MINUTES); } @Override public Object getObject(Object key) { log.info("mybatis...cache...get...key:{}",key); return this.getRedisTemplate().opsForValue().get(String.valueOf(key)) ; } @Override public Object removeObject(Object key) { log.info("mybatis...cache...remove...key:{}",key); return this.getRedisTemplate().delete(String.valueOf(key)); } @Override public void clear() { Set<String> keys = this.getRedisTemplate().keys("*" + id + "*"); if (keys != null && keys.size()>0){ log.info("mybatis...cache...clear...keys:{}",keys); this.getRedisTemplate().delete(keys) ; } } @Override public int getSize() { Set<String> keys = this.getRedisTemplate().keys("*" + id + "*"); if (keys != null){ log.info("mybatis...cache...size...keys:{}",keys.size()); return keys.size() ; } return 0; } }
五、參考源碼
文檔倉庫:
https://gitee.com/cicadasmile/butte-java-note
到此這篇關于SpringBoot3集成Redis的方法詳解的文章就介紹到這了,更多相關SpringBoot3集成Redis內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
如何使用axis調用WebService及Java?WebService調用工具類
Axis是一個基于Java的Web服務框架,可以用來調用Web服務接口,下面這篇文章主要給大家介紹了關于如何使用axis調用WebService及Java?WebService調用工具類的相關資料,需要的朋友可以參考下2023-04-04java Object轉byte與byte轉Object方式
這篇文章主要介紹了java Object轉byte與byte轉Object方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08