Redis分布式锁工具类
Redis 分布式锁 RedisTemplate 实现
1、配置redis序列化
@Configuration
public class RedisConfig {
@Bean
public <T> RedisTemplate<String, T> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, T> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//非final类型的对象,把对象类型也序列化进去,以便反序列化推测正确的类型
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
//null字段不显示
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//POJO无public属性或方法时不报错
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
redisTemplate.setKeySerializer(redisSerializer);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(redisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
2、包含key和requestid的实体类
@Getter
@Setter
@Builder
public class RedisLockEntity {
private String lockKey;
private String requestId;
}
3、加锁解锁的工具类
@Service
@Slf4j
public class RedisService {
@Autowired
private RedisTemplate redisTemplate;
/**
* 加锁,自旋重试三次
*
* @param redisLockEntity 锁实体
* @return
*/
public boolean lock(RedisLockEntity redisLockEntity) {
boolean locked = false;
int tryCount = 3;
while (!locked && tryCount > 0) {
locked = redisTemplate.opsForValue().setIfAbsent(redisLockEntity.getLockKey(), redisLockEntity.getRequestId(), 2, TimeUnit.MINUTES);
tryCount--;
try {
Thread.sleep(300);
} catch (InterruptedException e) {
log.error("线程被中断" + Thread.currentThread().getId(), e);
}
}
return locked;
}
/**
* 非原子解锁,可能解别人锁,不安全
*
* @param redisLockEntity
* @return
*/
public boolean unlock(RedisLockEntity redisLockEntity) {
if (redisLockEntity == null || redisLockEntity.getLockKey() == null || redisLockEntity.getRequestId() == null)
return false;
boolean releaseLock = false;
String requestId = (String) redisTemplate.opsForValue().get(redisLockEntity.getLockKey());
if (redisLockEntity.getRequestId().equals(requestId)) {
releaseLock = redisTemplate.delete(redisLockEntity.getLockKey());
}
return releaseLock;
}
/**
* 使用lua脚本解锁,不会解除别人锁
*
* @param redisLockEntity
* @return
*/
public boolean unlockLua(RedisLockEntity redisLockEntity) {
if (redisLockEntity == null || redisLockEntity.getLockKey() == null || redisLockEntity.getRequestId() == null)
return false;
DefaultRedisScript<Long> redisScript = new DefaultRedisScript();
//用于解锁的lua脚本位置
redisScript.setLocation(new ClassPathResource("unlock.lua"));
redisScript.setResultType(Long.class);
//没有指定序列化方式,默认使用上面配置的
Object result = redisTemplate.execute(redisScript, Arrays.asList(redisLockEntity.getLockKey()), redisLockEntity.getRequestId());
return result.equals(Long.valueOf(1));
}
}
4、用于解锁的lua脚本(放于resources下面)
文件名:unlock.lua
if redis.call('get',KEYS[1]) == ARGV[1] then
return redis.call('del',KEYS[1])
else
return 0
end
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 奇怪的阿峰
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果