Redisson - Redis Java client with features of In-Memory Data Grid. Over 50 Redis based Java objects and services: Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Publish / Subscribe, Bloom filter, Spring Cache, Tomcat, Scheduler, JCache API, Hibernate, MyBatis, RPC, local cache …
Redisson 的优势
提供了看门狗
Redisson提供了一个监控锁的看门狗(watch dog),它的作用是在Redisson实例被关闭前,不断(默认每10s)的延长锁(redis中的目标key)的有效期(默认续期到30s),也就是说,如果一个拿到锁的线程一直没有完成逻辑,那么看门狗会帮助线程不断的延长锁的超时时间,锁不会因为超时而被释放。加锁的业务只要运行完成,就不会给当前锁续期,即使不手动解锁,锁默认会在30s内自动过期,不会产生死锁问题;
默认情况下,看门狗的续期时间是30s,也可以通过修改Config.lockWatchdogTimeout来另行指定。
另外Redisson还提供了可以指定leaseTime参数的加锁方法来指定加锁的时间。超过这个时间后锁便自动解开了,不会延长锁的有效期。
提供了多种锁
redisson 还有公平锁、读写锁的实现。
1
|
compile 'org.redisson:redisson:3.17.6'
|
1
2
3
4
5
|
@Bean(destroyMethod = "shutdown")
public RedissonClient redissonClient() throws Exception {
Config config = Config.fromYAML(new File("redisson-config.yaml"));
return Redisson.create(config);
}
|
Spring Boot
1
|
compile 'org.redisson:redisson-spring-boot-starter:3.17.6'
|
1
2
3
4
5
6
|
spring:
application:
name: springboot-redisson
redis:
redisson:
file: classpath:redisson.yml
|
1
2
3
4
5
6
7
8
|
singleServerConfig:
password: 123456
address: "redis://127.0.0.1:6379"
database: 1
threads: 0
nettyThreads: 0
codec: !<org.redisson.codec.JsonJacksonCodec> {}
transportMode: "NIO"
|
注意下 codec 配置,默认编码 org.redisson.codec.JsonJacksonCodec。
Available Spring Beans:
- RedissonClient
- RedissonRxClient
- RedissonReactiveClient
- RedisTemplate
- ReactiveRedisTemplate
封装 redissonClient 的使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
/**
* Redisson分布式锁接口
* <p>
* RLock的实现有可重入非公平锁(RedissonLock)、可重入公平锁(RedissonFairLock)、联锁(RedissonMultiLock)、 红锁(RedissonRedLock)、 读锁(RedissonReadLock)、 写锁(RedissonWriteLock)等
*/
public interface DistributedLocker {
RLock lock(String lockKey);
RLock lock(String lockKey, long timeout);
RLock lock(String lockKey, TimeUnit unit, long timeout);
boolean tryLock(String lockKey, TimeUnit unit, long leaseTime);
boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime);
void unlock(String lockKey);
void unlock(RLock lock);
/**
* @param lockKey
* @param unit
* @param waitTime
* @param leaseTime
* @param supplier 获取锁后要执行的业务逻辑
* @param scene 业务逻辑的场景,用于打印日志
* @param <T>
* @return
*/
<T> T tryLockAndRun(@Nonnull String lockKey, @Nonnull TimeUnit unit, long waitTime, long leaseTime, @Nonnull Supplier<T> supplier, String scene);
}
/**
* Redisson分布式锁实现-使用可重入非公平锁(RedissonLock)
*/
@Component
public class RedissonDistributedLocker implements DistributedLocker {
@Autowired
private RedissonClient redissonClient;
@Override
public RLock lock(String lockKey) {
RLock lock = this.redissonClient.getLock(lockKey);
lock.lock();
return lock;
}
@Override
public RLock lock(String lockKey, long timeout) {
RLock lock = this.redissonClient.getLock(lockKey);
lock.lock(timeout, TimeUnit.SECONDS);
return lock;
}
@Override
public RLock lock(String lockKey, TimeUnit unit, long timeout) {
RLock lock = this.redissonClient.getLock(lockKey);
lock.lock(timeout, unit);
return lock;
}
@Override
public boolean tryLock(String lockKey, TimeUnit unit, long leaseTime) {
RLock lock = this.redissonClient.getLock(lockKey);
try {
return lock.tryLock(0L, leaseTime, unit);
} catch (InterruptedException var7) {
return false;
}
}
@Override
public boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime){
RLock lock = redissonClient.getLock(lockKey);
try {
return lock.tryLock(waitTime, leaseTime, unit);
} catch (InterruptedException e) {
return false;
}
}
@Override
public void unlock(String lockKey){
RLock lock = redissonClient.getLock(lockKey);
try {
if (lock.isLocked()) {
lock.unlock();
}
} catch (IllegalMonitorStateException localIllegalMonitorStateException) {}
}
@Override
public void unlock(RLock lock) {
try {
if (lock.isLocked()) {
lock.unlock();
}
} catch (IllegalMonitorStateException var3) {}
}
@Override
public <T> T tryLockAndRun(@Nonnull String lockKey, @Nonnull TimeUnit unit, long waitTime, long leaseTime, @Nonnull Supplier<T> supplier, String scene) {
final long start = SystemClock.now();
// 获取分布式锁,最长等待时间:10秒,20秒后自动释放。注意锁与事务的顺序:获取分布式锁 -> 开启事务 -> 执行业务 -> 提交事务 -> 释放分布式锁!!!
final boolean tryLock = this.tryLock(lockKey, unit, waitTime, leaseTime);
final long end = SystemClock.now();
if (!tryLock) {
log.error("[{}]获取分布式锁失败,lockKey = {},耗时{}ms", scene, lockKey, end - start);
throw new RequestResultException(JsonCommonCodeEnum.E0004);
}
// 注意:一定是获取锁成功后,才进行try{}finally{释放锁}
try {
log.info("[{}]获取分布式锁成功,lockKey = {},耗时{}ms", scene, lockKey, end - start);
return supplier.get();
} finally {
this.unlock(lockKey);
}
}
}
|
附录