使用redisTempate帮我写个RedisLock工具类 java springboot
时间: 2025-07-05 17:50:06 浏览: 7
<think>嗯,用户想让我介绍如何使用RedisTemplate在Spring Boot中编写一个RedisLock工具类。首先,我需要回忆一下Redis分布式锁的基本原理。Redis通常用SET命令配合NX和PX参数来实现锁的获取,设置一个唯一的value来避免误删其他客户端的锁。锁释放时则需要用Lua脚本保证原子性。
接下来,用户可能是在Spring Boot项目中使用Redis,所以需要引入Spring Data Redis的依赖。RedisTemplate是Spring提供的操作Redis的工具类,这里应该用StringRedisTemplate,因为锁的value可能需要序列化为字符串。
然后,设计工具类的方法。通常需要tryLock和unlock方法。tryLock方法需要指定锁的key、等待时间、超时时间等参数。在获取锁时,使用SET命令,并设置过期时间,防止死锁。如果获取失败,可能需要重试,直到超时。
释放锁的时候,要确保只有锁的持有者才能删除,所以需要验证value是否匹配。这里必须使用Lua脚本来保证原子性,避免在判断value和删除之间发生锁过期的情况。
可能还需要考虑锁的可重入性,但用户可能只需要基础的锁功能,所以暂时可以不实现。另外,自动续期也是一个高级功能,可能超出当前需求范围,但可以提一下。
然后,代码结构方面,工具类应该被声明为Spring的@Component,并通过构造函数注入StringRedisTemplate。tryLock方法生成UUID作为value,循环尝试获取锁,使用Boolean结果判断是否成功。unlock方法里执行Lua脚本,比较value并删除key。
还需要注意异常处理,确保在获取锁的过程中出现异常也能正确释放资源。另外,锁的有效期要合理设置,避免业务逻辑未完成锁就过期了。
用户可能对Lua脚本不太熟悉,需要解释一下它的作用,保证操作的原子性。同时,提醒用户在使用时处理可能的异常,并根据业务调整参数。
最后,提供一个使用示例,展示如何在Service中注入并使用RedisLock,加锁后执行业务逻辑,并在finally块中释放锁。这样用户就能清楚整个流程了。</think>我为您提供一个基于Spring Boot和RedisTemplate实现的分布式锁工具类,包含详细注释和使用示例:
```java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* Redis分布式锁工具类
*/
@Component
public class RedisLock {
private final StringRedisTemplate redisTemplate;
// Lua脚本保证原子性删除(判断值+删除锁)
private static final DefaultRedisScript<Long> UNLOCK_SCRIPT = new DefaultRedisScript<>(
"if redis.call('get', KEYS[1]) == ARGV[1] then " +
" return redis.call('del', KEYS[1]) " +
"else " +
" return 0 " +
"end",
Long.class
);
@Autowired
public RedisLock(StringRedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* 尝试获取分布式锁
* @param lockKey 锁的key
* @param waitTime 最大等待时间(毫秒)
* @param leaseTime 锁持有时间(毫秒)
* @return 锁标识(解锁时需传递) 获取失败返回null
*/
public String tryLock(String lockKey, long waitTime, long leaseTime) {
String lockValue = UUID.randomUUID().toString();
long end = System.currentTimeMillis() + waitTime;
while (System.currentTimeMillis() < end) {
Boolean success = redisTemplate.opsForValue().setIfAbsent(
lockKey,
lockValue,
leaseTime,
TimeUnit.MILLISECONDS
);
if (Boolean.TRUE.equals(success)) {
return lockValue;
}
try {
Thread.sleep(50); // 休眠避免频繁尝试
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
return null;
}
/**
* 释放分布式锁
* @param lockKey 锁的key
* @param lockValue 锁标识
*/
public void unlock(String lockKey, String lockValue) {
redisTemplate.execute(
UNLOCK_SCRIPT,
Collections.singletonList(lockKey),
lockValue
);
}
}
```
### 关键实现说明:
1. **锁标识机制**:使用UUID作为锁的唯一标识,避免误删其他客户端的锁
2. **原子性加锁**:使用`setIfAbsent`(对应Redis的SET NX命令)保证原子性
3. **锁超时机制**:设置leaseTime防止死锁
4. **安全解锁**:通过Lua脚本实现原子性的`判断值+删除`操作
5. **重试机制**:循环尝试获取锁直到超时
### 使用示例:
```java
@Service
public class OrderService {
@Autowired
private RedisLock redisLock;
private static final String ORDER_LOCK_KEY = "order_lock_";
public void createOrder(String orderId) {
String lockValue = null;
try {
// 尝试获取锁(最大等待1秒,锁有效期3秒)
lockValue = redisLock.tryLock(ORDER_LOCK_KEY + orderId, 1000, 3000);
if (lockValue != null) {
// 获取锁成功,执行业务逻辑
// ...
} else {
throw new RuntimeException("获取锁失败");
}
} finally {
if (lockValue != null) {
// 释放锁
redisLock.unlock(ORDER_LOCK_KEY + orderId, lockValue);
}
}
}
}
```
### 注意事项:
1. **锁有效期**:根据业务执行时间合理设置leaseTime
2. **时钟偏移**:依赖Redis服务器时间,可能存在时钟不同步问题
3. **重试策略**:根据业务需求调整重试间隔(示例中使用50ms)
4. **异常处理**:确保在finally块中释放锁
5. **高可用**:Redis集群建议使用Redlock算法
如果需要更高级的功能(如可重入锁、自动续期等),可以考虑集成Redisson框架,但此实现已满足大部分分布式锁场景的基本需求。
阅读全文
相关推荐

















