在Redis中,SETNX
是 “Set If Not Exists”(如果不存在,则设置)的缩写。这是一个原子操作,用于设置一个键的值,前提是这个键不存在。如果键已经存在,.则不会执行任何操作。
封装方法trylock
,用于获取分布式锁
/**
* 尝试获 取一个锁。
*
* @param name 锁的名称,通常是一个资源的标识。
* @param expire 锁的过期时间,单位为毫秒。
* @return 如果获取锁成功,返回一个唯一的token;如果失败,则返回null。
*/
public String tryLock(String name, long expire) {
// 为锁名称添加后缀,以避免命名冲突
name = name + "_lock";
// 生成一个唯一的token,用于标识持有锁的客户端
String token = UUID.randomUUID().toString();
// 获取Redis连接工厂
RedisConnectionFactory factory = stringRedisTemplate.getConnectionFactory();
// 获取Redis连接
RedisConnection conn = factory.getConnection();
try {
// 使用SET命令尝试以NX选项(只在键不存在时设置)设置键值对,如果成功,返回true
// 这里使用了Expiration指定键的过期时间,以确保锁在一段时间后自动释放
// 参考redis命令:SET key value [EX seconds] [PX milliseconds] [NX|XX]
Boolean result = conn.set(
name.getBytes(), //key
token.getBytes(), //value
Expiration.from(expire, TimeUnit.MILLISECONDS),
RedisStringCommands.SetOption.SET_IF_ABSENT // NX
);
// 如果设置成功,返回生成的token
if (result != null && result)
return token;
} finally {
// 释放Redis连接
RedisConnectionUtils.releaseConnection(conn, factory, false);
}
// 如果未能成功获取锁,返回null
return null;
}
接下来,你可以在需要防止并发执行的方法中使用tryLock
方法:
public void exampleMethod(String taskName) {
String lockKey = "myLockKey";
// 尝试获取锁
String token = tryLock(lockKey, 10000); // 锁过期时间为10秒
if (token != null) {
try {
// 获取锁成功,执行业务逻辑
System.out.println("所获取成功");
// 模拟任务执行
// ...
} finally {
// 释放锁
stringRedisTemplate.delete(lockKey+ "_lock");
}
} else {
// 获取锁失败,处理失败逻辑
System.out.println("获取锁失败");
}
}