如何利用redis 实现分布式项目枷锁功能

mac2025-04-10  3

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

最新回复(0)