分布式项目,由于用户需要占座需求,防止用户同时进入该链接,导致事务失效,单独使用事务的话,项目在两台服务器上面,导致事务实现不了这种锁,因此添加上了redis单线程锁。
具体实现流程 redis 工具类方法
// 锁名称
public static final String LOCK_PREFIX = "redis_lock";
// 加锁失效时间,毫秒
public static final int LOCK_EXPIRE = 10000; // ms
/**
* 最终加强分布式锁
*
* @param key
* key值
* @return 是否获取到
*/
public boolean lock(String key) {
String lock = LOCK_PREFIX + key;
// 利用lambda表达式
return (Boolean) redisTemplate.execute((RedisCallback) connection -> {
long expireAt = System.currentTimeMillis() + LOCK_EXPIRE + 1;
log.info("失效的时间是【{}】",String.valueOf(expireAt));
Boolean acquire = connection.setNX(lock.getBytes(), String.valueOf(expireAt).getBytes());
log.info("查看acquire========"+acquire);
if (acquire) {
return true;
} else {
byte[] value = connection.get(lock.getBytes());
log.info("查看value========"+value);
if (Objects.nonNull(value) && value.length > 0) {
long expireTime = Long.parseLong(new String(value));
log.info("查看expireTime========"+expireTime);
// 如果锁已经过期
if (expireTime < System.currentTimeMillis()) {
log.info("如果锁已经过期,重新加锁");
// 重新加锁,防止死锁
byte[] oldValue = connection.getSet(lock.getBytes(),
String.valueOf(System.currentTimeMillis() + LOCK_EXPIRE + 1).getBytes());
log.info("查看oldValue========"+oldValue);
Boolean newLoing= Long.parseLong(new String(oldValue)) < System.currentTimeMillis();
log.info("查看Long.parseLong========"+newLoing);
return newLoing;
}
}
}
return false;
});
}
/**
* 删除锁
*
* @param key
*/
public void deleteLock(String key) {
redisTemplate.delete(key);
}
调用工具方法
@Override
public Boolean testRedis(String code) {
System.out.println("测试分布式锁的应用说明============查看锁状态"+redisManager.exists("redis_lockbbbbbbbbbb"));
Boolean flag=true;
System.out.println("测试分布式锁的应用说明============查看continue之后是否执行此日志");
try {
while (true) {
if(redisManager.lock("bbbbbbbbbb")) {
Thread.sleep(5000);
code.substring(0, 2);
System.out.println("测试分布式锁的应用说明=============这是被锁住的进程"+code);
System.out.println("测试分布式锁的应用说明=============查看是否进行下面逻辑"+code);
redisManager.deleteLock("redis_lockbbbbbbbbbb");
return true;
}else {
Thread.sleep(1000);
System.out.println("测试分布式锁的应用说明=============这是等待进行释放锁");
continue;
}
}
} catch (Exception e) {
System.out.println("测试分布式锁的应用说明=============抛出异常后发音日志");
e.printStackTrace();
}
System.out.println("测试分布式锁的应用说明=============跳出循环后执行这个方法这是直接返回数据");
return false;
}
这是整个过程的使用,具体实现逻辑:
当用户进入的时候,根据规则生成redis 的key ,同时添加过时时间,如果两个人同时进入,那么第一次进入的人的redis是开锁状态,第二个人进入的时候是闭锁状态, 因此第一个人会在serviceimpl中执行 Thread.sleep(5000);方法,相当于具体的逻辑,当逻辑执行完之后,将锁释放掉,第二个用户会一直走下面的循环,直到锁开了之后才会进入具体的逻辑,
工具类中的逻辑 针对上锁时间而言,并不是在超时之后就将redis 清空,工具的逻辑为当超过过期时间之后,会再次给redis的key加锁,这样第二个请求就会进入,当然这样的问题就是当第一个没有执行完没有自动释放锁的时候,锁自动又加上了, 第二个请求会直接进入,因此枷锁的时间需要想好,尽量在一个请求可以执行完的情况下的时间的几倍。当然所有的逻辑中的要加上try catch 如果逻辑出错,需要在catch中将锁解开。大致就是这个意思!