版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
一、应用场景
当多个机器(多个进程)会对同一条数据进行修改时,并且要求这个修改是原子性的。这里有两个限定:(1)多个进程之间的竞争,意味着JDK自带的锁失效;(2)原子性修改,意味着数据是有状态的,修改前后有依赖。
二、实现方式
分布式锁一般有三种实现方式:1. 数据库乐观锁;基于version字段实现,乐观锁,两个线程可以同时读取到原有的version值,但是最终只有一个可以完成操作;
2. 基于Redis的NX EX
参数的分布式锁
3. 基于ZooKeeper的分布式锁。
本篇博客将介绍第二种方式,基于Redis实现分布式锁。
三、代码实现
1、pom.xml
引入如下依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.0.6.RELEASE</version>
</dependency>
2、加锁
private static final String LOCK_SUCCESS = "OK";
/**
* setIfAbsent 函数, , 尝试设置lockKey的值为lockValue,
* 若成功则同时设置key的过期时间并返回true,否则返回false
* @author fxbin
* @param lockKey 锁
* @param lockValue 锁标识
* @param expireTime 过期时间,单位 ms
* @return 是否获取成功
*/
public boolean tryGetDistributedLock(String lockKey, String lockValue, Integer expireTime){
Assert.isTrue(StringUtils.isNotBlank(lockKey), "lockKey must not be null");
Assert.isTrue(StringUtils.isNotBlank(lockValue), "lockValue must not be null");
Assert.isTrue(expireTime > 0, "expireTime must greater than 0");
log.info("尝试获取锁, 锁Key:{}, 锁标识:{}", lockKey, lockValue);
RedisScript<String> script = new DefaultRedisScript<>(
"return redis.call('set',KEYS[1],ARGV[1],'NX','PX',ARGV[2])", String.class);
String locked = (String) redisTemplate.execute(script,
redisTemplate.getStringSerializer(),
redisTemplate.getStringSerializer(),
Collections.singletonList(lockKey),
lockValue, String.valueOf(expireTime));
return LOCK_SUCCESS.equalsIgnoreCase(locked);
}
3、解锁
/**
* 释放分布式锁
* @author fxbin
* @param lockKey 锁
* @param lockValue 锁标识
* @return 是否释放成功
*/
public boolean releaseDistributedLock(String lockKey, String lockValue){
log.info("尝试释放锁, 锁Key:{}, 锁标识:{}", lockKey, lockValue);
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end ";
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
redisScript.setScriptText(script);
redisScript.setResultType(Long.class);
Long evalResult = redisTemplate.execute(redisScript, Collections.singletonList(lockKey), lockValue);
log.info("lua执行结果: {}", evalResult);
if (RELEASE_SUCCESS.equals(evalResult)) {
return true;
}
return false;
}
– end 感谢阅读,如有问题,请留言或发邮件
–