基于springBoot的redisson分布式锁
之前使用Redis分布式锁都是自己写的工具类,利用Redis的setNX特性;后来发现Redisson提供的分布式锁是真的好用。
Redisson可以看做是对Redis的一个操作工具类。将原生的RedisHash,List,Set,String等数据结构封装为Java里大家最熟悉的映射(Map),列表(List),集(Set)等。
Redisson集成SpringBoot主要有两种方式:
一个是使用redisson-spring-boot-starter依赖,然后在配置文件中写上Redis的配置信息即可,具体参考这篇文章/Muscleheng/article/details/139248641 推荐 推荐。
再一种方式就是引入redisson原始依赖,自己写配置类注入到spring容器中,这里就使用这种方式。
一、配置文件
文件添加依赖
<dependency>
<groupId></groupId>
<artifactId>redisson</artifactId>
<version>3.16.1</version>
</dependency>
配置文件配置
spring
redis:
database: 0
host: 1.1.1.1
port: 6379
password: 123456
#集群模式时使用
cluster:
nodes: 1.1.1.1:6379, 1.1.1.1:6379, 1.1.1.1:6379, 1.1.1.1:6379, 1.1.1.1:6379
二、RedisTemplate序列化配置
// 配置序列化
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
(1);
(new StringRedisSerializer());
(new GenericJackson2JsonRedisSerializer());
(redisConnectionFactory);
return template;
}
三、RedissonConfig配置
@ConfigurationProperties(prefix = "")
@Component
@Data
public class RedissonConfig {
// 读取配置文件里面的Redis信息
private String password;
private Cluster cluster;
public static class Cluster {
private List<String> nodes;
public List<String> getNodes() {
return nodes;
}
public void setNodes(List<String> nodes) {
= nodes;
}
}
/**
* 配置redisson
* @return
*/
@Bean
public Redisson redisson() {
List<String> clusterNodes = new ArrayList<>();
for (int i = 0; i < ().getNodes().size(); i++) {
("redis://" + ().getNodes().get(i));
}
Config config = new Config();
ClusterServersConfig clusterServersConfig = ()
.addNodeAddress((new String[()]));
(getPassword());
return (Redisson) (config);
}
}
四、编写RedissonUtil工具类
@Component
public class RedissonUtil {
private static final Logger logger = ();
/**
* redis锁前缀
*/
public static final String SYS_LOCK_FLAG = "MY_LOCK";
/**
* 用于隔开缓存前缀与缓存键值
*/
public static final String KEY_SPLIT = ":";
// 静态属性注入
private static Redisson redisson;
@Autowired
public void setRedisson(Redisson redisson) {
= redisson;
}
/**
* 加锁,一直等待直到获得锁为止,不建议使用
*
* @param lockName 锁名 相同的key表示相同的锁,建议针对不同的业务使用不同的key
* @param expiresTime 过期时间,单位:秒
* @return
*/
public static boolean getLock(String lockName, long expiresTime) {
String key = getLockKey(lockName);
//获取锁对象
RLock lock = (key);
//设置锁过期时间,防止死锁的产生
(expiresTime, );
("获取锁成功,Redis Lock key :{}", key);
return true;
}
/**
* 加锁,规定时间内没抢到锁就放弃
*
* @param lockName 锁名 相同的key表示相同的锁,建议针对不同的业务使用不同的key
* @param waitTime 最大等待锁时间
* @param expiresTime 锁过期时间,单位:秒
* @return
* @throws InterruptedException
*/
public static boolean getTryLock(String lockName, long waitTime, long expiresTime) {
String key = getLockKey(lockName);
//获取锁对象
RLock lock = (key);
//设置锁过期时间,防止死锁的产生
boolean lockFlag = false;
try {
lockFlag = (waitTime, expiresTime, );
} catch (InterruptedException e) {
("加锁出现异常", e);
} finally {
if (lockFlag) {
unlock(lockName);
}
}
String msg = "获取锁失败";
if (lockFlag) {
msg = "获取锁成功";
}
("{},Redis Lock key :{}", msg, key);
return lockFlag;
}
/**
* 释放锁,建议放在 finally里面
*
* @param lockName 锁名称
*/
public static void unlock(String lockName) {
String key = getLockKey(lockName);
//获取所对象
RLock lock = (key);
// 释放锁,判断要解锁的key是否已被锁定并且是否被当前线程保持
if (() && ()) {
();
("释放Redis锁成功,key:{}", key);
}
}
/**
* 对锁的key添加系统标识前缀
*
* @return
*/
private static String getLockKey(String key) {
return RedissonUtil.SYS_LOCK_FLAG + RedissonUtil.KEY_SPLIT + key;
}
}
五、使用
@Test
public void redissonLock(){
String key = "zhh11";
long waitTime = 10;
long expiresTime = 10;
// 加锁
if ((key, waitTime, expiresTime)){
try{
(3000L);
// 业务代码
}catch (Exception e){
();
}finally {
// 释放锁
(key);
// 捕获异常之后需要 手动回滚事务
// ().setRollbackOnly();
}
}else {
("未获取到锁");
}
}