很多人喜欢把redisson
继续封装成注解,不说好坏,只想说锁得粒度还是越小越好。
项目中引入包
版本使用3.11.1
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
</dependency>
配置文件添加
spring.redis.cluster.nodes = xxx.xxx.xxx.xxx,xxx.xxx.xxx.xxx,xxx.xxx.xxx.xxx,xxx.xxx.xxx.xxx,xxx.xxx.xxx.xxx,xxx.xxx.xxx.xxx
spring.redis.password = passwd
示例①
@Autowired
private RedissonClient redissonClient;
public void lockTest(){
RLock lock = redissonClient.getLock(RedisConst.LOCK_PREFIX+"lock:order:xxxxxx");
try {
// 这里要根据实际业务使用isLocked()
if (lock.tryLock(5,30, TimeUnit.SECONDS)) {
//todo 这里实现你的业务逻辑,锁使用原则,粒度越小越好
}
} catch (InterruptedException e) {
System.out.println("获取锁异常");
}finally {
lock.unlock();
}
}
示例②乐观锁场景
RLock lock = redissonClient.getLock(RedisConst.LOCK_PREFIX + "COMMIT_LOCK");
boolean res=false;
try {
res = lock.tryLock(0, 10, TimeUnit.SECONDS);
System.out.println(res);
if (res){
System.out.println("获取到锁了");
}
if (!res) {
return BusinessResultModel.fail("操作太频繁!");
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
trylock参数说明
-
-- waitTime
:第一个参数最长等待取锁时间。如果再这个时间内取到锁将返回true
,如果超过这个时间还没取到锁将返回false
-
-- leastTime
: 第二个参数,取到锁之后锁过期时间,当超过这个时间还没执行完业务锁将被释放。 -
-- TimeUnit
: 第三个参数,时间单位。
由于代码业务得复杂性,会存在以下情况:
- 1、三个线程并发得情况下,我们假设线程
A、B、C
A线程获取锁,B
线程进来取不到锁,这个时候B
线程执行到finally
方法把A
的锁释放了,这个时候C
线程去取锁取到锁了,那么AC
线程同时执行同一段代码。
解决方案:实际上不存在这个问题,因为在redisson
中锁只能由当前取到锁得线程释放了,所以调用lock.unlock()
不用在加判断了。
- 2、
AB
两个线程非并发执行,假设A线程执行完成返回后,B
线程进来了,执行了同一段代码,实际上AB
两个线程是同一个请求内容。这实际是一个幂等问题。
这个时候会由于业务问题导致数据库出现脏数据。例如根据同一个订单号去生成付款单,那么将会生成两条id
不一样的付款单。
解决方案:针对相同请求通过业务进行判断,以上述例子为例:条件为同一个订单号,判断该订单是否已处理,如果已处理,则直接返回处理成功。或者返回已处理。
- 3、根据
trylock
的参数我们可以知道,如果我想立马获得取锁结果,只要将第一个参数设置为0
即可