一、引入依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.5.0</version>
</dependency>
二、工具类
package com.hl.redisdemo.util;import redis.clients.jedis.Jedis; import redis.clients.jedis.params.SetParams;import java.util.Collections;public class RedissonLockUtil {private static final Jedis jedis = new Jedis("localhost", 6379);/*** 可重入锁加锁* @param lockKey 锁的key* @param requestId 请求标识* @param expireTime 超时时间* @return 是否成功获取锁*/public static boolean lock(String lockKey, String requestId, int expireTime) {SetParams params = new SetParams();params.nx().px(expireTime); // 设置nx和px参数,保证只在不存在该key时设置值,并设置过期时间String result = jedis.set(lockKey, requestId, params);return "OK".equalsIgnoreCase(result);}/*** 可重入锁解锁* @param lockKey 锁的key* @param requestId 请求标识* @return 是否成功释放锁*/public static boolean unlock(String lockKey, String requestId) {String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";Object result = jedis.eval(luaScript, Collections.singletonList(lockKey), Collections.singletonList(requestId));Long RELEASE_SUCCESS = 1L;return RELEASE_SUCCESS.equals(result);}/*** 获取可重入锁* @param lockKey 锁的key* @param requestId 请求标识* @param expireTime 超时时间* @return 是否成功获取锁*/public static boolean tryLock(String lockKey, String requestId, int expireTime) {SetParams params = new SetParams();params.nx().px(expireTime); // 设置nx和px参数,保证只在不存在该key时设置值,并设置过期时间String result = jedis.set(lockKey, requestId, params);return "OK".equalsIgnoreCase(result);} }
三、测试代码
package com.hl.redisdemo.controller;import com.hl.redisdemo.util.RedissonLockUtil; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;import java.util.UUID;/*** @author hulei* @date 2024/2/6 17:23*/@RestController public class RedisDemoController {@RequestMapping("/redisTest")public String redisTest() throws InterruptedException {String str;String lockKey = "myLock";String requestId = UUID.randomUUID().toString(); // 生成唯一请求标识// 集群场景下,锁超时时间应该保证大于多数节点获取锁的时间//当发生在多数节点获取锁的时间大于锁超时时间时,获取到的锁在各节点早已超时失效,锁失效int expireTime = 5000; // 锁的过期时间为5秒,注意,// 尝试获取锁if (RedissonLockUtil.tryLock(lockKey, requestId, expireTime)) {System.out.println("获取到锁");// 执行业务逻辑Thread.sleep(1000);// 释放锁if (RedissonLockUtil.unlock(lockKey, requestId)) {System.out.println("释放锁成功");str = "释放锁成功";} else {System.out.println("释放锁失败");str = "释放锁失败";}} else {System.out.println("获取锁失败");str = "获取锁失败";}return str;} }
测试结果分析:
1.正常测试结果
正常匀速点击请求,每次等之前的请求完成后释放锁,后面的请求则能够正常获取锁
2.异常测试结果 :
如果点击速度过快,之前的请求业务逻辑没有执行完,锁还未释放,后面的请求获取锁时,则提示锁获取失败,这样就保证了业务执行的顺序性,正确性。使用场景 如防止订单超卖,库存扣减等