Spring Boot + Redis 實(shí)現(xiàn)各種操作,寫得太好了吧!
關(guān)注我們,設(shè)為星標(biāo),每天7:30不見不散,架構(gòu)路上與您共享? 回復(fù)"架構(gòu)師"獲取資源
一、Jedis,Redisson,Lettuce三者的區(qū)別
共同點(diǎn):都提供了基于Redis操作的Java API,只是封裝程度,具體實(shí)現(xiàn)稍有不同。
不同點(diǎn):
1.1、Jedis
是Redis的Java實(shí)現(xiàn)的客戶端。支持基本的數(shù)據(jù)類型如:String、Hash、List、Set、Sorted Set。
特點(diǎn):使用阻塞的I/O,方法調(diào)用同步,程序流需要等到socket處理完I/O才能執(zhí)行,不支持異步操作。Jedis客戶端實(shí)例不是線程安全的,需要通過連接池來使用Jedis。
1.2、Redisson
優(yōu)點(diǎn)點(diǎn):分布式鎖,分布式集合,可通過Redis支持延遲隊(duì)列。
1.3、 Lettuce
用于線程安全同步,異步和響應(yīng)使用,支持集群,Sentinel,管道和編碼器。
基于Netty框架的事件驅(qū)動(dòng)的通信層,其方法調(diào)用是異步的。Lettuce的API是線程安全的,所以可以操作單個(gè)Lettuce連接來完成各種操作。
二、RedisTemplate
2.1、使用配置
maven配置引入,(要加上版本號(hào),我這里是因?yàn)镻arent已聲明)
????org.springframework.boot
????spring-boot-starter-data-redis
application-dev.yml
spring:
??redis:
????host:?192.168.1.140
????port:?6379
????password:
????database:?15?#?指定redis的分庫(共16個(gè)0到15)
2.2、使用示例
?@Resource
?private?StringRedisTemplate?stringRedisTemplate;
?
????@Override
????public?CustomersEntity?findById(Integer?id)?{
????????//?需要緩存
????????//?所有涉及的緩存都需要?jiǎng)h除,或者更新
????????try?{
????????????String?toString?=?stringRedisTemplate.opsForHash().get(REDIS_CUSTOMERS_ONE,?id?+?"").toString();
????????????if?(toString?!=?null)?{
????????????????return?JSONUtil.toBean(toString,?CustomersEntity.class);
????????????}
????????}?catch?(Exception?e)?{
????????????e.printStackTrace();
????????}
????????//?緩存為空的時(shí)候,先查,然后緩存redis
????????Optional?byId?=?customerRepo.findById(id);
????????if?(byId.isPresent())?{
????????????CustomersEntity?customersEntity?=?byId.get();
????????????try?{
????????????????stringRedisTemplate.opsForHash().put(REDIS_CUSTOMERS_ONE,?id?+?"",?JSONUtil.toJsonStr(customersEntity));
????????????}?catch?(Exception?e)?{
????????????????e.printStackTrace();
????????????}
????????????return?customersEntity;
????????}
????????return?null;
????}
2.3、擴(kuò)展
2.3.1、spring-boot-starter-data-redis的依賴包

3.3.2、stringRedisTemplate API(部分展示)
opsForHash --> hash操作 opsForList --> list操作 opsForSet --> set操作 opsForValue --> string操作 opsForZSet --> Zset操作

3.3.3 StringRedisTemplate默認(rèn)序列化機(jī)制
public?class?StringRedisTemplate?extends?RedisTemplate?{
?????/**
??????*?Constructs?a?new?StringRedisTemplate?instance.?{@link?#setConnectionFactory(RedisConnectionFactory)}
??????*?and?{@link?#afterPropertiesSet()}?still?need?to?be?called.
??????*/
?????public?StringRedisTemplate()?{
??????RedisSerializer?stringSerializer?=?new?StringRedisSerializer();
??????setKeySerializer(stringSerializer);
??????setValueSerializer(stringSerializer);
??????setHashKeySerializer(stringSerializer);
??????setHashValueSerializer(stringSerializer);
?????}
?}
三、RedissonClient 操作示例
3.1 基本配置
3.1.1、Maven pom 引入
????org.springframework.boot
????spring-boot-starter-data-redis
????org.redisson
????redisson
????3.8.2
????true
????org.redisson
????redisson-spring-boot-starter
????LATEST
3.1.2、添加配置文件Yaml或者json格式
redisson-config.yml。
#?Redisson?配置
singleServerConfig:
??address:?"redis://192.168.1.140:6379"
??password:?null
??clientName:?null
??database:?15?#選擇使用哪個(gè)數(shù)據(jù)庫0~15
??idleConnectionTimeout:?10000
??pingTimeout:?1000
??connectTimeout:?10000
??timeout:?3000
??retryAttempts:?3
??retryInterval:?1500
??reconnectionTimeout:?3000
??failedAttempts:?3
??subscriptionsPerConnection:?5
??subscriptionConnectionMinimumIdleSize:?1
??subscriptionConnectionPoolSize:?50
??connectionMinimumIdleSize:?32
??connectionPoolSize:?64
??dnsMonitoringInterval:?5000
??#dnsMonitoring:?false
threads:?0
nettyThreads:?0
codec:
??class:?"org.redisson.codec.JsonJacksonCodec"
transportMode:?"NIO"
或者,配置 redisson-config.json
{
??"singleServerConfig":?{
????"idleConnectionTimeout":?10000,
????"pingTimeout":?1000,
????"connectTimeout":?10000,
????"timeout":?3000,
????"retryAttempts":?3,
????"retryInterval":?1500,
????"reconnectionTimeout":?3000,
????"failedAttempts":?3,
????"password":?null,
????"subscriptionsPerConnection":?5,
????"clientName":?null,
????"address":?"redis://192.168.1.140:6379",
????"subscriptionConnectionMinimumIdleSize":?1,
????"subscriptionConnectionPoolSize":?50,
????"connectionMinimumIdleSize":?10,
????"connectionPoolSize":?64,
????"database":?0,
????"dnsMonitoring":?false,
????"dnsMonitoringInterval":?5000
??},
??"threads":?0,
??"nettyThreads":?0,
??"codec":?null,
??"useLinuxNativeEpoll":?false
}
新建讀取配置類
@Configuration
public?class?RedissonConfig?{
????@Bean
????public?RedissonClient?redisson()?throws?IOException?{
????????//?兩種讀取方式,Config.fromYAML?和?Config.fromJSON
//????????Config?config?=?Config.fromJSON(RedissonConfig.class.getClassLoader().getResource("redisson-config.json"));
????????Config?config?=?Config.fromYAML(RedissonConfig.class.getClassLoader().getResource("redisson-config.yml"));
????????return?Redisson.create(config);
????}
}
或者,在 application.yml中配置如下
spring:
??redis:
????redisson:
??????config:?classpath:redisson-config.yaml
3.2 使用示例
@RestController
@RequestMapping("/")
public?class?TeController?{
????@Autowired
????private?RedissonClient?redissonClient;
????static?long?i?=?20;
????static?long?sum?=?300;
//????==========================?String?=======================
????@GetMapping("/set/{key}")
????public?String?s1(@PathVariable?String?key)?{
????????//?設(shè)置字符串
????????RBucket?keyObj?=?redissonClient.getBucket(key);
????????keyObj.set(key?+?"1-v1");
????????return?key;
????}
????@GetMapping("/get/{key}")
????public?String?g1(@PathVariable?String?key)?{
????????//?設(shè)置字符串
????????RBucket?keyObj?=?redissonClient.getBucket(key);
????????String?s?=?keyObj.get();
????????return?s;
????}
????//????==========================?hash?=======================-=
????@GetMapping("/hset/{key}")
????public?String?h1(@PathVariable?String?key)?{
????????Ur?ur?=?new?Ur();
????????ur.setId(MathUtil.randomLong(1,20));
????????ur.setName(key);
??????//?存放?Hash
????????RMap?ss?=?redissonClient.getMap("UR");
????????ss.put(ur.getId().toString(),?ur);
????????return?ur.toString();
????}
????@GetMapping("/hget/{id}")
????public?String?h2(@PathVariable?String?id)?{
????????//?hash?查詢
????????RMap?ss?=?redissonClient.getMap("UR");
????????Ur?ur?=?ss.get(id);
????????return?ur.toString();
????}
????//?查詢所有的?keys
????@GetMapping("/all")
????public?String?all(){
????????RKeys?keys?=?redissonClient.getKeys();
????????Iterable?keys1?=?keys.getKeys();
????????keys1.forEach(System.out::println);
????????return?keys.toString();
????}
????//?==================?==============讀寫鎖測(cè)試?=============================
????@GetMapping("/rw/set/{key}")
????public?void?rw_set(){
//????????RedissonLock.
????????RBucket?ls_count?=?redissonClient.getBucket("LS_COUNT");
????????ls_count.set("300",360000000l,?TimeUnit.SECONDS);
????}
????//?減法運(yùn)算
????@GetMapping("/jf")
????public?void?jf(){
????????String?key?=?"S_COUNT";
//????????RAtomicLong?atomicLong?=?redissonClient.getAtomicLong(key);
//????????atomicLong.set(sum);
//????????long?l?=?atomicLong.decrementAndGet();
//????????System.out.println(l);
????????RAtomicLong?atomicLong?=?redissonClient.getAtomicLong(key);
????????if?(!atomicLong.isExists())?{
????????????atomicLong.set(300l);
????????}
????????while?(i?==?0)?{
????????????if?(atomicLong.get()?>?0)?{
????????????????long?l?=?atomicLong.getAndDecrement();
????????????????????????try?{
????????????????????????????Thread.sleep(1000l);
????????????????????????}?catch?(InterruptedException?e)?{
????????????????????????????e.printStackTrace();
????????????????????????}
????????????????i?--;
????????????????System.out.println(Thread.currentThread().getName()?+?"->"?+?i?+?"->"?+?l);
????????????}
????????}
????}
????@GetMapping("/rw/get")
????public?String?rw_get(){
????????String?key?=?"S_COUNT";
????????Runnable?r?=?new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????RAtomicLong?atomicLong?=?redissonClient.getAtomicLong(key);
????????????????if?(!atomicLong.isExists())?{
????????????????????atomicLong.set(300l);
????????????????}
????????????????if?(atomicLong.get()?>?0)?{
????????????????????long?l?=?atomicLong.getAndDecrement();
????????????????????i?--;
????????????????????System.out.println(Thread.currentThread().getName()?+?"->"?+?i?+?"->"?+?l);
????????????????}
????????????}
????????};
????????while?(i?!=?0)?{
????????????new?Thread(r).start();
//????????????new?Thread(r).run();
//????????????new?Thread(r).run();
//????????????new?Thread(r).run();
//????????????new?Thread(r).run();
????????}
????????RBucket?bucket?=?redissonClient.getBucket(key);
????????String?s?=?bucket.get();
????????System.out.println("================線程已結(jié)束================================"?+?s);
????????return?s;
????}
}
4.3 擴(kuò)展
4.3.1 豐富的jar支持,尤其是對(duì) Netty NIO框架
4.3.2 豐富的配置機(jī)制選擇,這里是詳細(xì)的配置說明
https://github.com/redisson/redisson/wiki/2.-Configuration
關(guān)于序列化機(jī)制中,就有很多


4.3.3 API支持(部分展示),具體的 Redis --> RedissonClient ,可查看這里
https://github.com/redisson/redisson/wiki/11.-Redis-commands-mapping

4.3.4 輕便的豐富的鎖機(jī)制的實(shí)現(xiàn)
Lock Fair Lock MultiLock RedLock ReadWriteLock Semaphore PermitExpirableSemaphore CountDownLatch
四、基于注解實(shí)現(xiàn)的Redis緩存
4.1 Maven 和 YML配置
參考 RedisTemplate 配置。另外,還需要額外的配置類
//?todo?定義序列化,解決亂碼問題
@EnableCaching
@Configuration
@ConfigurationProperties(prefix?=?"spring.cache.redis")
public?class?RedisCacheConfig?{
????private?Duration?timeToLive?=?Duration.ZERO;
????public?void?setTimeToLive(Duration?timeToLive)?{
????????this.timeToLive?=?timeToLive;
????}
????@Bean
????public?CacheManager?cacheManager(RedisConnectionFactory?factory)?{
????????RedisSerializer?redisSerializer?=?new?StringRedisSerializer();
????????Jackson2JsonRedisSerializer?jackson2JsonRedisSerializer?=?new?Jackson2JsonRedisSerializer(Object.class);
????????//?解決查詢緩存轉(zhuǎn)換異常的問題
????????ObjectMapper?om?=?new?ObjectMapper();
????????om.setVisibility(PropertyAccessor.ALL,?JsonAutoDetect.Visibility.ANY);
????????om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
????????jackson2JsonRedisSerializer.setObjectMapper(om);
????????//?配置序列化(解決亂碼的問題)
????????RedisCacheConfiguration?config?=?RedisCacheConfiguration.defaultCacheConfig()
????????????????.entryTtl(timeToLive)
????????????????.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
????????????????.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
????????????????.disableCachingNullValues();
????????RedisCacheManager?cacheManager?=?RedisCacheManager.builder(factory)
????????????????.cacheDefaults(config)
????????????????.build();
????????return?cacheManager;
????}
}
4.2 使用示例
@Transactional
@Service
public?class?ReImpl?implements?RedisService?{
????@Resource
????private?CustomerRepo?customerRepo;
????@Resource
????private?StringRedisTemplate?stringRedisTemplate;
????public?static?final?String?REDIS_CUSTOMERS_ONE?=?"Customers";
????public?static?final?String?REDIS_CUSTOMERS_ALL?=?"allList";
????//?=====================================================================使用Spring?cahce?注解方式實(shí)現(xiàn)緩存
????//?==================================單個(gè)操作
????@Override
????@Cacheable(value?=?"cache:customer",?unless?=?"null?==?#result",key?=?"#id")
????public?CustomersEntity?cacheOne(Integer?id)?{
????????final?Optional?byId?=?customerRepo.findById(id);
????????return?byId.isPresent()???byId.get()?:?null;
????}
????@Override
????@Cacheable(value?=?"cache:customer",?unless?=?"null?==?#result",?key?=?"#id")
????public?CustomersEntity?cacheOne2(Integer?id)?{
????????final?Optional?byId?=?customerRepo.findById(id);
????????return?byId.isPresent()???byId.get()?:?null;
????}
?????//?todo?自定義redis緩存的key,
????@Override
????@Cacheable(value?=?"cache:customer",?unless?=?"null?==?#result",?key?=?"#root.methodName?+?'.'?+?#id")
????public?CustomersEntity?cacheOne3(Integer?id)?{
????????final?Optional?byId?=?customerRepo.findById(id);
????????return?byId.isPresent()???byId.get()?:?null;
????}
????//?todo?這里緩存到redis,還有響應(yīng)頁面是String(加了很多轉(zhuǎn)義符\,),不是Json格式
????@Override
????@Cacheable(value?=?"cache:customer",?unless?=?"null?==?#result",?key?=?"#root.methodName?+?'.'?+?#id")
????public?String?cacheOne4(Integer?id)?{
????????final?Optional?byId?=?customerRepo.findById(id);
????????return?byId.map(JSONUtil::toJsonStr).orElse(null);
????}
?????//?todo?緩存json,不亂碼已處理好,調(diào)整序列化和反序列化
????@Override
????@Cacheable(value?=?"cache:customer",?unless?=?"null?==?#result",?key?=?"#root.methodName?+?'.'?+?#id")
????public?CustomersEntity?cacheOne5(Integer?id)?{
????????Optional?byId?=?customerRepo.findById(id);
????????return?byId.filter(obj?->?!StrUtil.isBlankIfStr(obj)).orElse(null);
????}
????//?==================================刪除緩存
????@Override
????@CacheEvict(value?=?"cache:customer",?key?=?"'cacheOne5'?+?'.'?+?#id")
????public?Object?del(Integer?id)?{
????????//?刪除緩存后的邏輯
????????return?null;
????}
????@Override
????@CacheEvict(value?=?"cache:customer",allEntries?=?true)
????public?void?del()?{
????}
????@CacheEvict(value?=?"cache:all",allEntries?=?true)
????public?void?delall()?{
????}
????//?==================List操作
????@Override
????@Cacheable(value?=?"cache:all")
????public?List?cacheList()?{
????????List?all?=?customerRepo.findAll();
????????return?all;
????}
????//?todo?先查詢緩存,再校驗(yàn)是否一致,然后更新操作,比較實(shí)用,要清楚緩存的數(shù)據(jù)格式(明確業(yè)務(wù)和緩存模型數(shù)據(jù))
????@Override
????@CachePut(value?=?"cache:all",unless?=?"null?==?#result",key?=?"#root.methodName")
????public?List?cacheList2()?{
????????List?all?=?customerRepo.findAll();
????????return?all;
????}
}
4.3 擴(kuò)展
基于spring緩存實(shí)現(xiàn)

文章來源:http://blog.csdn.net/qq_42105629/article/details/102589319

到此文章就結(jié)束了。如果今天的文章對(duì)你在進(jìn)階架構(gòu)師的路上有新的啟發(fā)和進(jìn)步,歡迎轉(zhuǎn)發(fā)給更多人。歡迎加入架構(gòu)師社區(qū)技術(shù)交流群,眾多大咖帶你進(jìn)階架構(gòu)師,在后臺(tái)回復(fù)“加群”即可入群。
這些年小編給你分享過的干貨
1.SpringBoot物流管理項(xiàng)目,拿去學(xué)習(xí)吧(附源碼)
2.ERP系統(tǒng),自帶進(jìn)銷存+財(cái)務(wù)+生產(chǎn)功能,拿來即用(附源碼)
3.帶工作流的SpringBoot后臺(tái)管理項(xiàng)目快速開發(fā)(附源碼)
4.最好的OA系統(tǒng),拿來即用,非常方便(附源碼)
5.SpringBoot+Vue完整的外賣系統(tǒng),手機(jī)端和后臺(tái)管理,附源碼!
6.SpringBoot+Vue 可視化拖拽編輯的大屏項(xiàng)目(附源碼)

轉(zhuǎn)發(fā)在看就是最大的支持??
