主题切换
🔒 分布式锁
📖 功能介绍
TIP
基于Redis实现的分布式锁服务,支持注解和工具类两种使用方式,可以有效解决分布式系统中的并发控制问题。
⚙️ 全局配置
基础配置参数
参数名 | 说明 | 默认值 | 示例 |
---|---|---|---|
max-expire | 锁最大过期时间 | 30s | 60s |
acquire-timeout | 获取锁超时时间 | 30s | 10s |
yaml
wueasy:
lock:
max-expire: 30s # 最大过期时间,0表示永不过期
acquire-timeout: 30s # 获取锁超时时间,0表示一直等待
📝 使用方式
1. 注解方式 (@Lock)
注解参数说明
参数名 | 说明 | 默认值 | 示例 |
---|---|---|---|
group | 锁分组 | 方法名称 | "userLock" |
keys | 锁的key(支持SpEL) | - | "#p0.accountNo" |
maxExpire | 最大过期时间 | 全局配置 | 30000 |
acquireTimeout | 获取锁超时时间 | 全局配置 | 5000 |
msg | 获取锁失败提示 | "请求超时,请重试" | "操作频繁" |
使用示例
java
@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping("/login")
@Lock(
group = "userLogin",
keys = "#p0.accountNo",
maxExpire = 30000,
acquireTimeout = 5000,
msg = "登录请求频繁,请稍后再试"
)
public Mono<ResultVo<SessionVo>> login(@RequestBody @Valid LoginDto dto) {
return Mono.just(ResultVo.ok(loginService.login(dto)));
}
}
2. 工具类方式 (RedisDistributedLock)
核心方法
java
public class RedisDistributedLock {
/**
* 获取锁
* @param lockKey 锁标识
* @param maxExpire 过期时间
* @param acquireTimeout 获取超时时间
* @return 是否获取成功
*/
boolean lock(String lockKey, Duration maxExpire, Duration acquireTimeout);
/**
* 释放锁
* @param lockKey 锁标识
* @return 是否释放成功
*/
boolean unlock(String lockKey);
}
使用示例
java
@Service
public class UserService {
@Autowired
private RedisDistributedLock lock;
public void updateUser(UserDto dto) {
String lockKey = "user:" + dto.getId();
boolean acquired = false;
try {
// 获取锁,30秒过期,5秒超时
acquired = lock.lock(lockKey,
Duration.ofSeconds(30),
Duration.ofSeconds(5));
if (!acquired) {
throw new RuntimeException("操作频繁,请稍后再试");
}
// 执行业务逻辑
doUpdate(dto);
} finally {
// 释放锁
if (acquired) {
lock.unlock(lockKey);
}
}
}
}
💡 最佳实践
1. 锁粒度控制
- 避免锁粒度过大影响性能
- 确保锁的唯一性
- 合理设置过期时间
2. 异常处理
- 必须在finally中释放锁
- 捕获并处理获取锁异常
- 添加获取锁失败重试机制
3. 性能优化
- 合理设置超时时间
- 避免长时间持有锁
- 考虑使用锁的替代方案
⚠️ 注意事项
锁的释放
- 确保锁的及时释放
- 使用try-finally结构
- 避免锁泄露
超时设置
- 过期时间要大于业务执行时间
- 合理设置获取锁超时时间
- 避免死锁情况
🔍 常见问题
锁无法获取
- 检查Redis连接状态
- 验证锁key是否正确
- 确认超时时间设置
锁释放失败
- 检查锁是否已过期
- 验证释放锁的方法调用
- 查看Redis日志