SpringBoot3集成Redis的方法詳解
一、簡(jiǎn)介
緩存在項(xiàng)目開(kāi)發(fā)中,基本上是必選組件之一,Redis作為一個(gè)key-value存儲(chǔ)系統(tǒng),具備極高的數(shù)據(jù)讀寫(xiě)效率,并且支持的數(shù)據(jù)類(lèi)型比較豐富,在業(yè)務(wù)場(chǎng)景中的應(yīng)用非常廣泛;
Redis典型的應(yīng)用場(chǎng)景就是數(shù)據(jù)緩存能力,用來(lái)解決業(yè)務(wù)中最容易出現(xiàn)的查詢(xún)性能問(wèn)題,提升系統(tǒng)的響應(yīng)效率;其次就是分布式鎖機(jī)制,用來(lái)解決分布式系統(tǒng)中多線(xiàn)程并發(fā)處理資源的安全問(wèn)題;
二、工程搭建
1、工程結(jié)構(gòu)

2、依賴(lài)管理
Redis的客戶(hù)端使用的是lettuce組件的6.2.4.RELEASE版本,該組件具備可擴(kuò)展和線(xiàn)程安全的特性,支持Redis各種高級(jí)功能,如哨兵,集群,流水線(xiàn),自動(dòng)重新連接等;
<!-- 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組件中默認(rèn)使用的是common-pool2連接池組件,在配置中定義幾個(gè)常用的核心參數(shù);
spring:
# Redis配置
data:
redis:
host: 127.0.0.1
port: 6379
database: 1
# 讀超時(shí)
timeout: 3000
# 連接超時(shí)
connectTimeout: 5000
# Lettuce連接池
lettuce:
pool:
# 最小空閑連接
min-idle: 5
# 最大空閑連接
max-idle: 10
# 最大連接數(shù)
max-active: 100
# 連接分配應(yīng)該阻塞的最大時(shí)間
max-wait: 2000配置類(lèi)
@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、鎖的過(guò)期時(shí)間:20秒
return new RedisLockRegistry(factory, "REDIS-LOCK",20000L);
}
}三、Redis用法
1、環(huán)境搭建
Redis文檔中推薦使用brew工具安裝的方式,本地環(huán)境中是4.1版本,可以搜索到redis@6.2,即安裝該版本,并且可以使用brew命令管理Redis的啟動(dòng)和停止;
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原生的指令進(jìn)行啟動(dòng)和客戶(hù)端操作,在測(cè)試完成之后,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、數(shù)據(jù)類(lèi)型
Strings:字符串是最基本的數(shù)據(jù)類(lèi)型,表示一個(gè)字節(jié)序列,也是最常使用的類(lèi)型,單個(gè)最大能夠存儲(chǔ)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:鏈表結(jié)構(gòu),可以有序的存儲(chǔ)多個(gè)字符串值,基于數(shù)據(jù)左寫(xiě)入右讀取的方式可以模擬消息隊(duì)列,單個(gè)最大長(zhǎng)度為2^32-1;
public void dataList (){
// 1、左側(cè)寫(xiě)數(shù)據(jù)
redisTemplate.opsForList().leftPushAll("data-list","value-01","value-02","value-03");
// 2、右側(cè)讀數(shù)據(jù)
Object rightPop01 = redisTemplate.opsForList().rightPop("data-list") ;
Object rightPop02 = redisTemplate.opsForList().rightPop("data-list") ;
log.info("rightPop01:{},rightPop02:{}",rightPop01,rightPop02);
}Sets:用來(lái)存儲(chǔ)無(wú)序的、唯一的字符串集合,通常用來(lái)跟蹤分析唯一項(xiàng)的業(yè)務(wù)場(chǎng)景,比如唯一標(biāo)簽下的用戶(hù)群,獨(dú)立IP等;
public void dataSet (){
// 1、寫(xiě)數(shù)據(jù)
redisTemplate.opsForSet().add("data-set","Java","C++","Python","C++");
// 2、讀數(shù)據(jù)
Object pop01 = redisTemplate.opsForSet().pop("data-set");
Object pop02 = redisTemplate.opsForSet().pop("data-set");
log.info("pop01:{},pop02:{}",pop01,pop02);
}Hashes:Redis本身的K-V結(jié)構(gòu)上,在value中可以再次使用K-V數(shù)據(jù)類(lèi)型,在涉及大規(guī)模的關(guān)系型數(shù)據(jù)存儲(chǔ)時(shí),會(huì)優(yōu)先使用該類(lèi)型;
public void dataHash (){
// 1、寫(xiě)數(shù)據(jù)
HashMap<String,String> hashMap = new HashMap<>() ;
hashMap.put("key1","value1") ;
hashMap.put("key2","value2") ;
redisTemplate.opsForHash().putAll("data-hash",hashMap);
// 2、讀數(shù)據(jù)
Object kv1 = redisTemplate.opsForHash().get("data-hash","key1");
Object kv2 = redisTemplate.opsForHash().get("data-hash","key2");
log.info("kv1:{},kv2:{}",kv1,kv2);
}Sorted-sets:唯一的字符串集合,但是可以通過(guò)每個(gè)字符串的相關(guān)分?jǐn)?shù)來(lái)維持順序,這里的分?jǐn)?shù)可以表示排行順序,也可以標(biāo)識(shí)為對(duì)象的權(quán)重或優(yōu)先級(jí);
public void dataSortedSet (){
// 1、寫(xiě)數(shù)據(jù)
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、讀數(shù)據(jù)
Object popMax = redisTemplate.opsForZSet().popMax("sorted-set");
Object popMin = redisTemplate.opsForZSet().popMin("sorted-set");
log.info("popMax:{},popMin:{}",popMax,popMin);
}3、加鎖機(jī)制
使用SETNX方法即代碼中的setIfAbsent,如果key不存在,則設(shè)置key保存字符串的值,也就相當(dāng)于SET,當(dāng)key已經(jīng)存在時(shí),不執(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組件提供的封裝類(lèi),基于Redis實(shí)現(xiàn)分布式鎖的能力;有關(guān)于兩種鎖機(jī)制的測(cè)試,可以查看代碼工程中RedisLockTest單元測(cè)試類(lèi),
@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);
}
/**
* 重試機(jī)制多次加鎖
*/
@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、基礎(chǔ)配置
在Mybatis框架中,一級(jí)緩存是指SqlSession級(jí)別內(nèi);二級(jí)緩存是指Mapper級(jí)別內(nèi),需要在配置文件中開(kāi)啟,二級(jí)緩存并不適用于頻繁修改數(shù)據(jù)的業(yè)務(wù)場(chǎng)景;
配置文件
mybatis-plus:
configuration:
cache-enabled: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImplMapper注解,這里使用自定義的MybatisCache類(lèi),并且使用Redis組件來(lái)緩存數(shù)據(jù);
@CacheNamespace(implementation = MybatisCache.class)
public interface ArticleMapper extends BaseMapper<Article> {
}2、自定義實(shí)現(xiàn)
通過(guò)實(shí)現(xiàn)Cache接口,來(lái)定義二級(jí)緩存的處理策略,可以運(yùn)行MybatisTest測(cè)試類(lèi)中的方法,分析其執(zhí)行的原理,符合Cache-Aside模式,即先查詢(xún)緩存,如果未命中就查詢(xún)數(shù)據(jù)庫(kù),并將結(jié)果寫(xiě)入緩存,數(shù)據(jù)更新時(shí)會(huì)刪除相關(guān)緩存;
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;
}
}五、參考源碼
文檔倉(cāng)庫(kù):
https://gitee.com/cicadasmile/butte-java-note
到此這篇關(guān)于SpringBoot3集成Redis的方法詳解的文章就介紹到這了,更多相關(guān)SpringBoot3集成Redis內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 基于SpringBoot+Redis實(shí)現(xiàn)一個(gè)簡(jiǎn)單的限流器
- SpringBoot中Redis的緩存更新策略詳解
- SpringBoot中Redis自動(dòng)配置的介紹、原理和使用詳解
- SpringBoot引入Redis報(bào)Redis?command?timed?out兩種異常情況
- 使用Spring?Boot實(shí)現(xiàn)Redis鍵過(guò)期回調(diào)功能示例詳解
- redis之基于SpringBoot實(shí)現(xiàn)Redis stream實(shí)時(shí)流事件處理方式
- SpringBoot整合Redis實(shí)現(xiàn)緩存分頁(yè)數(shù)據(jù)查詢(xún)功能
- 基于SpringBoot + Redis實(shí)現(xiàn)密碼暴力破解防護(hù)
- Spring Boot 中的 Redis 分布式鎖
相關(guān)文章
如何使用axis調(diào)用WebService及Java?WebService調(diào)用工具類(lèi)
Axis是一個(gè)基于Java的Web服務(wù)框架,可以用來(lái)調(diào)用Web服務(wù)接口,下面這篇文章主要給大家介紹了關(guān)于如何使用axis調(diào)用WebService及Java?WebService調(diào)用工具類(lèi)的相關(guān)資料,需要的朋友可以參考下2023-04-04
JPA?通過(guò)Specification如何實(shí)現(xiàn)復(fù)雜查詢(xún)
這篇文章主要介紹了JPA?通過(guò)Specification如何實(shí)現(xiàn)復(fù)雜查詢(xún),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
java前后端使用ajax數(shù)據(jù)交互問(wèn)題(簡(jiǎn)單demo)
這篇文章主要介紹了java前后端使用ajax數(shù)據(jù)交互問(wèn)題(簡(jiǎn)單demo),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。2023-06-06
Java解決LocalDateTime傳輸前端為時(shí)間的數(shù)組
本文主要介紹了Java解決LocalDateTime傳輸前端為時(shí)間的數(shù)組,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-03-03
java Object轉(zhuǎn)byte與byte轉(zhuǎn)Object方式
這篇文章主要介紹了java Object轉(zhuǎn)byte與byte轉(zhuǎn)Object方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
Java基礎(chǔ)學(xué)習(xí)之標(biāo)簽
在Java中,標(biāo)簽必須在循環(huán)之前使用, 一個(gè)循環(huán)之中嵌套另一個(gè)循環(huán)的開(kāi)關(guān),從多重嵌套中continue或break,該文詳細(xì)介紹了標(biāo)簽的相關(guān)知識(shí),對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們還很有幫助,需要的朋友可以參考下2021-05-05

