原理简而言之就是:如果有人正在修改某个reids,就上锁,存一个标记到redis中,修改完了就解锁,删除标记。
实现步骤:
导入Redisson依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-data-21</artifactId>
<version>3.12.5</version>
</dependency>
新建redisson.yml
#Redisson配置
singleServerConfig:
address: "redis://round003.miracle-cn.com:6379"
password: CDmrk001
clientName: demo02-redisson
#选择使用哪个数据库0~15
database: 0
# 连接空闲超时,单位:毫秒
idleConnectionTimeout: 10000
# 连接超时,单位:毫秒
connectTimeout: 10000
# 命令等待超时,单位:毫秒
timeout: 3000
# 命令失败重试次数,如果尝试达到 retryAttempts(命令失败重试次数) 仍然不能将命令发送至某个指定的节点时,将抛出错误。
# 如果尝试在此限制之内发送成功,则开始启用 timeout(命令等待超时) 计时。
retryAttempts: 3
# 重新连接时间间隔,单位:毫秒
retryInterval: 1500
#reconnectionTimeout: 3000
# failedAttempts: 3
subscriptionsPerConnection: 5
# 发布和订阅连接的最小空闲连接数
subscriptionConnectionMinimumIdleSize: 1
# 发布和订阅连接池大小
subscriptionConnectionPoolSize: 50
# 最小空闲连接数
connectionMinimumIdleSize: 32
# 连接池大小
connectionPoolSize: 64
# DNS监测时间间隔,单位:毫秒
dnsMonitoringInterval: 5000
#dnsMonitoring: false
# 线程池数量,默认值: 当前处理核数量 * 2
threads: 0
# Netty线程池数量,默认值: 当前处理核数量 * 2
nettyThreads: 0
codec:
class: "org.redisson.codec.JsonJacksonCodec"
# 传输模式
transportMode: "NIO"
在RedisConfiguration中添加@bean
@Bean(destroyMethod = "shutdown")
public RedissonClient redissonClient(@Value("classpath:/redisson.yml") Resource configFile) throws IOException {
Config config = Config.fromYAML(configFile.getInputStream());
log.info("address:{}",config.useSingleServer().getAddress());
return Redisson.create(config);
}
封装RedisLockUtil工具类
package com.miracle.pay.util;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* @Author Diuut
* @Date 2020/5/13 13:52
*/
@Component
public class RedisLockUtil {
@Autowired
private RedissonClient redissonClient;
/**
* 加锁
*
* @param lockKey 锁Key
* @return
*/
public RLock lock(String lockKey) {
RLock rlock = redissonClient.getLock(lockKey);
rlock.lock();
return rlock;
}
/**
* 释放锁
*
* @param lockKey 锁Key
*/
public void unlock(String lockKey) {
RLock rlock = redissonClient.getLock(lockKey);
rlock.unlock();
}
/**
* 释放锁
*
* @param lock 锁对象
*/
public static void unlock(RLock lock) {
lock.unlock();
}
/**
* 带超时的锁
*
* @param lockKey 锁key
* @param timeout 超时时间 单位:秒
*/
public RLock lock(String lockKey, int timeout) {
RLock rLock = redissonClient.getLock(lockKey);
rLock.lock(timeout, TimeUnit.SECONDS);
return rLock;
}
/**
* 带超时的锁
*
* @param lockKey 锁key
* @param unit 时间单位
* @param timeout 超时时间
*/
public RLock lock(String lockKey, int timeout, TimeUnit unit) {
RLock rLock = redissonClient.getLock(lockKey);
rLock.lock(timeout, unit);
return rLock;
}
/**
* 尝试获取锁
*
* @param lockKey 锁key
* @param waitTime 最多等待时间 单位:秒
* @param leaseTime 上锁后自动释放锁时间 单位:秒
* @return
*/
public boolean tryLock(String lockKey, int waitTime, int leaseTime) throws InterruptedException {
RLock lock = redissonClient.getLock(lockKey);
return lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
}
/**
* 尝试获取锁
*
* @param lockKey 锁key
* @param unit 时间单位
* @param waitTime 最多等待时间
* @param leaseTime 上锁后自动释放锁时间
* @return
*/
public boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime) throws InterruptedException {
RLock lock = redissonClient.getLock(lockKey);
return lock.tryLock(waitTime, leaseTime, unit);
}
}
以上就完成了就可以使用了。使用例子:
public void saveUser(int userUid,User user){
try {
redisLockUtil.lock("userLock-uid:" + userUid);
log.info("userLock-uid: " + userUid + "上锁");
String userData = JSONObject.toJSONString(user);
redisTemplate.opsForValue().set("user-uid:" + userUid, userData, 7, TimeUnit.DAYS);
redisTemplate.opsForSet().add("redis-update-queue", "user-uid:"+userUid);
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
redisLockUtil.unlock("userLock-uid:" + userUid);
log.info("userLock-uid: " + 10135 + "解锁");
}
}