SpringBoot 的 RedisTemplate、Redisson

一、Jedis、Lettuce、Redisson的简介

优先使用Lettuce,
需要分布式锁,分布式集合等分布式的高级特性,添加Redisson结合使用。
对于高并发,1000/s的并发,数据库可能由行锁变成表锁,性能下降会厉害。

1.1、Jedis

老牌Redis的Java客户端,提供比较全面的Redis命令的支持,
使用阻塞的I/O,方法调用都是同步的,程序流需要等到sockets处理完I/O才能执行,不支持异步。
Jedis客户端实例不是线程安全的,使直接连接redis server,需要通过连接池来使用Jedis,为每个jedis实例增加物理连接。

1.2、Lettuce

   SpringBoot2之后,默认就采用了lettuce。 
高级Redis客户端,基于Netty框架的事件驱动的通信层,用于线程安全同步,异步和响应使用,支持集群,Sentinel,管道和编码器。
Lettuce的API是线程安全的,可以操作单个Lettuce连接来完成各种操作,连接实例(StatefulRedisConnection)可在多个线程间并发访问。

1.3、Redisson

基于Netty框架的事件驱动的通信层,方法是异步的,API线程安全,可操作单个Redisson连接来完成各种操作。
实现了分布式和可扩展的Java数据结构,不支持字符串操作,不支持排序、事务、管道、分区等Redis特性。
提供很多分布式相关操作服务,如,分布式锁,分布式集合,可通过 Redis支持延迟队列。

二、SpringBoot 的 RedisTemplate

2.1、配置

<!--redis(spring-boot-starter-data-redis中包含的Lettuce)-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--Lettuce使用线程池必要包-->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>
</dependency>
<!-- Redisson依赖 -->
<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.23.2</version>
</dependency>  
####################redis连接配置############
redis:
#   cluster:
#	nodes:
#	  - 127.0.0.1:7001
#	  - 127.0.0.1:7002
#	  - 127.0.0.1:7003
#	   host: 127.0.0.1port: 6379password: 123456database: 0timeout: 2000mslettuce:pool:# 连接池最大连接数max-active: 20# 连接池中的最小空闲连接max-idle: 10# 连接池最大阻塞等待时间(使用负数表示没有限制,单位ms)max-wait: 3000

2.2、代码使用

2..2.1.配置 RedisTemplate

@Configuration
public class RedisConfig {/*** 创建 RedisTemplate,注入IOC容器*/@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();// 设置数据源的连接工厂(默认会传入框架中自带的(也就是读取完配置文件装配的)LettuceConnectionFactory)// 也可以自己定义,注入容器,再通过@Qualifier("")传进来 template.setConnectionFactory(factory);//设置key的序列化器template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(new Jackson2JsonRedisSerializer(Object.class));// hash的key也采用String的序列化方式template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(new Jackson2JsonRedisSerializer(Object.class));return template;}
}

2..2.3.RedisTemplate 封装

@Component
public class RedisClient {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;/*** 指定缓存失效时间* @param key 键* @param time 时间(秒)*/public boolean expire(String key,long time){try {if(time>0){redisTemplate.expire(key, time, TimeUnit.SECONDS);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 根据key 获取过期时间* @param key 键 不能为null* @return 时间(秒) 返回0代表为永久有效*/public long ttl(String key){return redisTemplate.getExpire(key,TimeUnit.SECONDS);}//============================String=============================/*** 普通缓存获取* @param key 键* @return 值*/public Object get(String key){return key==null?null:redisTemplate.opsForValue().get(key);}/*** 普通缓存放入* @param key 键* @param value 值* @return true成功 false失败*/public boolean set(String key,Object value) {try {redisTemplate.opsForValue().set(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 删除缓存* @param key 可以传一个值 或多个*/public Boolean del(String key){return redisTemplate.delete(key);}//================================hash=================================/*** HashGet* @param key 键 不能为null* @param item 项 不能为null*/public Object hget(String key,String item){return redisTemplate.opsForHash().get(key, item);}/*** 向 hash 表中放入数据,如果不存在将创建* @param key 键* @param item 项* @param value 值* @return true 成功 false失败*/public boolean hset(String key,String item,Object value) {try {redisTemplate.opsForHash().put(key, item, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 删除hash表中的值* @param key 键 不能为null* @param item 项 可以使多个 不能为null*/public void hdel(String key, Object... item){redisTemplate.opsForHash().delete(key,item);}//============================set=============================/*** 根据key获取Set中的所有值* @param key 键*/public Set<Object> smembers(String key){try {return redisTemplate.opsForSet().members(key);} catch (Exception e) {e.printStackTrace();return null;}}/*** 将数据放入set缓存* @param key 键* @param values 值 可以是多个* @return 成功个数*/public long sadd(String key, Object...values) {try {return redisTemplate.opsForSet().add(key, values);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 移除值为value的* @param key 键* @param values 值 可以是多个* @return 移除的个数*/public long srem(String key, Object ...values) {try {Long count = redisTemplate.opsForSet().remove(key, values);return count;} catch (Exception e) {e.printStackTrace();return 0;}}//===============================list=================================/*** 获取list缓存的内容* @param key 键* @param start 开始* @param end 结束  0 到 -1代表所有值*/public List<Object> lrange(String key, long start, long end){try {return redisTemplate.opsForList().range(key, start, end);} catch (Exception e) {e.printStackTrace();return null;}}/*** 将list放入缓存* @param key 键* @param value 值*/public boolean rpush(String key, Object value) {try {redisTemplate.opsForList().rightPush(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 将list放入缓存* @param key 键* @param value 值*/public boolean lpush(String key, List<Object> value) {try {redisTemplate.opsForList().rightPushAll(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 移除N个值为value* @param key 键* @param count 移除多少个* @param value 值* @return 移除的个数*/public long lrem(String key,long count,Object value) {try {Long remove = redisTemplate.opsForList().remove(key, count, value);return remove;} catch (Exception e) {e.printStackTrace();return 0;}}
}

三、SpringBoot 的 Redisson 

Redisson官方文档: https://github.com/redisson/redisson/wiki

3.1、在之前的 Configuration 里添加 Bean

@Configuration
public class RedisConfig {// 锁前缀	private static final String SCHEMA_PREFIX = "redis://";// 超时时间private final long lockWatchTimeOut = 3000;	/*** 创建 RedisTemplate,注入IOC容器*/@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();// 设置数据源的连接工厂(默认会传入框架中自带的(也就是读取完配置文件装配的)LettuceConnectionFactory)// 也可以自己定义,注入容器,再通过@Qualifier("")传进来 template.setConnectionFactory(factory);//设置key的序列化器template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(new Jackson2JsonRedisSerializer(Object.class));// hash的key也采用String的序列化方式template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(new Jackson2JsonRedisSerializer(Object.class));return template;}/*** 创建 RedissonClient,注入IOC容器*/@Beanpublic RedissonClient redissonClient(RedisProperties redisProperties) {Config config = new Config();RedisProperties.Sentinel sentinel = redisProperties.getSentinel();RedisProperties.Cluster redisPropertiesCluster = redisProperties.getCluster();if (redisPropertiesCluster != null) {//集群redisClusterServersConfig clusterServersConfig = config.useClusterServers();for (String cluster : redisPropertiesCluster.getNodes()) {clusterServersConfig.addNodeAddress(SCHEMA_PREFIX + cluster);}if (StringUtils.hasText(redisProperties.getPassword())) {clusterServersConfig.setPassword(redisProperties.getPassword());}clusterServersConfig.setTimeout((int) redisProperties.getTimeout().toMillis());clusterServersConfig.setPingConnectionInterval(30000);} else if (StringUtils.hasText(redisProperties.getHost())) {//单点redisSingleServerConfig singleServerConfig = config.useSingleServer().setAddress(SCHEMA_PREFIX + redisProperties.getHost() + ":" + redisProperties.getPort());if (StringUtils.hasText(redisProperties.getPassword())) {singleServerConfig.setPassword(redisProperties.getPassword());}singleServerConfig.setTimeout((int) redisProperties.getTimeout().toMillis());singleServerConfig.setPingConnectionInterval(30000);singleServerConfig.setDatabase(redisProperties.getDatabase());} else if (sentinel != null) {//哨兵模式SentinelServersConfig sentinelServersConfig = config.useSentinelServers();sentinelServersConfig.setMasterName(sentinel.getMaster());for (String node : sentinel.getNodes()) {sentinelServersConfig.addSentinelAddress(SCHEMA_PREFIX + node);}if (StringUtils.hasText(redisProperties.getPassword())) {sentinelServersConfig.setPassword(redisProperties.getPassword());}sentinelServersConfig.setTimeout((int) redisProperties.getTimeout().toMillis());sentinelServersConfig.setPingConnectionInterval(30000);sentinelServersConfig.setDatabase(redisProperties.getDatabase());}config.setLockWatchdogTimeout(lockWatchTimeOut);return Redisson.create(config);}}

3.2、分布式锁

Redisson续期机制—看门狗机制:
1.启动定时任务重新给锁设置过期时间,默认过期时间是 30 秒,每 10 秒(默认事件的1/3)续期一次(补到 30 秒)
2.如果线程挂掉(服务器宕机),则不会续期。
3.只有lock.lock(); 会有看门狗机制;
4.lock.lock(10,,TimeUnit.SECONDS);手动设置过期时间的话,则不会有看门狗机制。

/*** 分布式Redis锁*/
@Slf4j
public class DistributedRedisLock {@Autowiredprivate RedissonClient redissonClient;// 加锁public Boolean lock(String lockName) {if (redissonClient == null) {log.info("DistributedRedisLock redissonClient is null");return false;}try {RLock lock = redissonClient.getLock(lockName);// 锁15秒后自动释放,防止死锁lock.lock(15, TimeUnit.SECONDS);// 加锁成功return true;} catch (Exception e) {e.printStackTrace();return false;}}// 释放锁public Boolean unlock(String lockName) {if (redissonClient == null) {log.info("DistributedRedisLock redissonClient is null");return false;}try {RLock lock = redissonClient.getLock(lockName);lock.unlock();// 释放锁成功return true;} catch (Exception e) {e.printStackTrace();return false;}}
}

3.3、读写锁 

@Autowired
RedissonClient redisson;@Autowired
RedisTemplate redisTemplate;@ResponseBody
@GetMapping("/write")
public String writeValue(){RReadWriteLock lock = redisson.getReadWriteLock("rw-lock");RLock rLock = lock.writeLock();String s = "";try {s = UUID.randomUUID().toString();// 模拟业务时间    Thread.sleep(30000);} catch (Exception e){e.printStackTrace();}finally {rLock.unlock();}redisTemplate.opsForValue().set("writeValue",s);return s;
}@GetMapping(value = "/read")
@ResponseBody
public String readValue() {String s = "";RReadWriteLock readWriteLock = redisson.getReadWriteLock("rw-lock");//加读锁RLock rLock = readWriteLock.readLock();try {rLock.lock();s = (String) redisTemplate.opsForValue().get("writeValue");TimeUnit.SECONDS.sleep(10);} catch (Exception e) {e.printStackTrace();} finally {rLock.unlock();}return s;
}

3.4、闭锁 

@GetMapping(value = "/lockDoor")
@ResponseBody
public String lockDoor() throws InterruptedException {RCountDownLatch lockDoor = redisson.getCountDownLatch("lockDoor");lockDoor.trySetCount(5); // 设置计数为5lockDoor.await(); //等待闭锁完成return "放假啦...";
}@GetMapping(value = "/go/{id}")
public String go(@PathVariable("id") Integer id)  {RCountDownLatch lockDoor = redisson.getCountDownLatch("lockDoor");lockDoor.countDown(); // 计数减1return id+"班都走光了";
}

3.5、信号量 

@GetMapping(value = "/park")
@ResponseBody
public String park() {RSemaphore park = redisson.getSemaphore("park");try {park.acquire();// 获取一个信号量(redis中信号量值-1),如果redis中信号量为0了,则在这里阻塞住,直到信号量大于0,可以拿到信号量,才会继续执行。} catch (InterruptedException e) {e.printStackTrace();}return "ok";
}@GetMapping(value = "/go")
@ResponseBody
public String go() {RSemaphore park = redisson.getSemaphore("park");park.release();  //释放一个信号量(redis中信号量值+1)return "ok";
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/48180.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

再JAVA中如何使用qsort对类进行排序?

目录 结论&#xff1a; 解析&#xff1a; 结论&#xff1a; import java.util.Arrays;class Person implements Comparable<Person>{public String name;public int age;public Person(String name, int age) {this.name name;this.age age;}Overridepublic Stri…

[保研/考研机试] KY11 二叉树遍历 清华大学复试上机题 C++实现

题目链接&#xff1a; 二叉树遍历_牛客题霸_牛客网编一个程序&#xff0c;读入用户输入的一串先序遍历字符串&#xff0c;根据此字符串建立一个二叉树&#xff08;以指针方式存储&#xff09;。题目来自【牛客题霸】https://www.nowcoder.com/share/jump/43719512169254700747…

机器学习笔记之优化算法(十五)Baillon Haddad Theorem简单认识

机器学习笔记之优化算法——Baillon Haddad Theorem简单认识 引言 Baillon Haddad Theorem \text{Baillon Haddad Theorem} Baillon Haddad Theorem简单认识证明过程证明&#xff1a;条件 1 ⇒ 1 \Rightarrow 1⇒ 条件 2 2 2证明&#xff1a;条件 3 ⇒ 3 \Rightarrow 3⇒条件 1…

css3+js 画出爱心特效

要使用CSS3和JavaScript绘制爱心特效&#xff0c;可以使用CSS3的动画和过渡效果来创建爱心的形状&#xff0c;并使用JavaScript来控制动画的触发和交互。以下是一个简单的示例代码&#xff1a; HTML: <div class"heart"></div> <button onclick&quo…

玩转单元测试之gmock

引言 前文我们学习了gtest相关的使用&#xff0c;单靠gtest&#xff0c;有些场景仍然无法进行测试&#xff0c;因此就诞生了gmock。 gmock快速入门 在引入gtest时&#xff0c;gmock也同样引入了&#xff0c;因此只需要在编译时加上合适的编译选项即可&#xff0c;注意不同版…

算法通关村十一关 | 位运算实现加法和乘法

1.位实现加法和乘法 在计算机中&#xff0c;位运算的效率要比加减乘除的效率更高&#xff0c;因此在高性能软件中源码中大量使用&#xff0c;计算机里各种运算基本上都是位运算。 学习下面内容之前建议先学习位运算规则&#xff1a;算法通关村十一关 | 位运算的规则_我爱学算…

【MaxKey对接一】对接gitlab的oauth登录

MaxKey的Oauth过程 引导进入 GET http://{{maxKey_host}}/sign/authz/oauth/v20/authorize?client_idYOUR_CLIENT_ID&response_typecode&redirect_uriYOUR_REGISTERED_REDIRECT_URI 登录后回调地址 YOUR_REGISTERED_REDIRECT_URI/?code{{code}} 换取Access Token GET…

winform使用usercontrol 构建了一个复杂的列表,列表速度慢该如何优化?

当使用 WinForms 构建复杂的列表时&#xff0c;可能会面临性能问题&#xff0c;特别是在数据量大或 UI 复杂的情况下。以下是一些优化策略&#xff0c;可以帮助您改善列表的性能&#xff1a; 1. **虚拟模式 (Virtual Mode)**&#xff1a;对于大型数据集&#xff0c;考虑使用虚…

「UG/NX」Block UI 曲线收集器CurveCollector

✨博客主页何曾参静谧的博客📌文章专栏「UG/NX」BlockUI集合📚全部专栏「UG/NX」NX二次开发「UG/NX」BlockUI集合「VS」Visual Studio「QT」QT5程序设计「C/C+&#

docker 01(初识docker)

一、docker概念 Docker是一个开源的应用容器引擎&#xff1b;诞生于2013年初&#xff0c;基于Go 语言实现&#xff0c;dotCloud公司出品(后改名为Dockerlnc);Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后发布到任何流行的Linux …

网络安全设备篇——加密机

加密机是一种专门用于数据加密和解密的网络安全设备。它通过使用密码学算法对数据进行加密&#xff0c;从而保护数据的机密性和完整性。加密机通常被用于保护敏感数据&#xff0c;如金融信息、个人身份信息等。 加密机的主要功能包括&#xff1a; 数据加密&#xff1a;加密机使…

探究Java spring中jdk代理和cglib代理!

面对新鲜事物&#xff0c;我们要先了解在去探索事物的本质-默 目录 一.介绍二者代理模式 1.1.Jdk代理模式 1.2cglib代理模式 1.3二者区别 1.3.1有无接口 1.3.2灵活性 1.4对于两种代理模式的总结 1.4.1jdk代理模式 1.4.2cglib代理模式 二.两种代理模式应用场景 2.1jd…

数学建模-多元线性回归笔记

数学建模笔记 1.学模型✅ 2.看专题论文并复习算法 多元线性回归 无偏性&#xff1a;预测值与真实值非常接近一致性&#xff1a;样本量无限增大&#xff0c;收敛于待估计参数的真值如何做&#xff1a;控制核心解释变量和u不相关 四类模型回归系数的解释 截距项不用考虑一元线性…

搜狗拼音占用了VSCode及微信小程序开发者工具快捷键Ctrl + Shit + K 搜狗拼音截图快捷键

修改搜狗拼音的快捷键 右键--更多设置--属性设置--按键--系统功能快捷键--系统功能快捷键设置--取消Ctrl Shit K的勾选--勾选截屏并设置为Ctrl Shit A 微信开发者工具设置快捷键 右键--Command Palette--删除行 微信开发者工具快捷键 删除行&#xff1a;Ctrl Shit K 或…

【开源项目】Stream-Query的入门使用和原理分析

前言 无意间发现了一个有趣的项目&#xff0c;Stream-Query。了解了一下其基本的功能&#xff0c;可以帮助开发者省去Mapper的编写。在开发中&#xff0c;我们会编写entity和mapper来完成业务代码&#xff0c;但是Stream-Query可以省去mapper&#xff0c;只写entity。 快速入…

CSDN编程题-每日一练(2023-08-22)

CSDN编程题-每日一练(2023-08-22) 一、题目名称:最长递增区间二、题目名称:K树三、题目名称:小Q的价值无向图一、题目名称:最长递增区间 时间限制:1000ms内存限制:256M 题目描述: 给一个无序数组,求最长递增的区间长度。如:[5,2,3,8,1,9] 最长区间 2,3,8 长度为 3。…

分布式事务理论基础

今天啊&#xff0c;本片博客我们一起来学习一下微服务中的一个重点和难点知识&#xff1a;分布式事务。 我们会基于Seata 这个框架来学习。 1、分布式事务问题 事务&#xff0c;我们应该比较了解&#xff0c;我们知道所有的事务&#xff0c;都必须要满足ACID的原则。也就是 …

Hadoop集群搭建(hadoop-3.3.5)

一、修改服务器配置文件 1、配置环境变量 vim /etc/profile #java环境变量 export JAVA_HOME/usr/local/jdk/jdk8 export JRE_HOME$JAVA_HOME/jre export CLASSPATH$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH export PATH$JAVA_HOME/bin:$JRE_HOME/bin:$PATH #hadoop环境变量 …

c++关键字 =delete和=default

在C的类中&#xff0c;有四类特殊的成员函数&#xff1a;① 默认构造函数&#xff1b;② 拷贝构造函数&#xff1b;③ 拷贝赋值函数&#xff08;operator&#xff09;&#xff1b;④ 析构函数&#xff1b;它们控制着类的实例的创建、初始化、拷贝以及销毁。 &#xff08;1&…

前端开发怎么解决前端安全性的问题? - 易智编译EaseEditing

前端安全性是保护前端应用程序免受恶意攻击和数据泄露的重要方面。以下是一些解决前端安全性问题的关键方法&#xff1a; 输入验证与过滤&#xff1a; 对所有用户输入进行验证和过滤&#xff0c;防止恶意用户通过注入攻击等手段破坏应用程序或获取敏感信息。 跨站点脚本&#…