分布式项目,由于用户需要占座需求,防止用户同时进入该链接,导致事务失效,单独使用事务的话,项目在两台服务器上面,导致事务实现不了这种锁,因此添加上了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中将锁解开。大致就是这个意思!