SpringBoot | Redis序列化与分布式锁
欢迎参观我的博客,一个Vue 与 SpringBoot结合的产物:https://poetize.cn
- 博客:https://gitee.com/littledokey/poetize-vue2.git
- 聊天室:https://gitee.com/littledokey/poetize-im-vue3.git
- 后端:https://gitee.com/littledokey/poetize.git
- 七牛云登录/注册地址(文件服务器,CDN):https://s.qiniu.com/Mz6Z32
原文链接:https://poetize.cn/article?id=40
RedisTemplate自定义序列化方式
@Configuration
@EnableCaching
@EnableConfigurationProperties(RedisProperties.class)
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper mapper = new ObjectMapper();
//ObjectMapper 将序列化对象的所有属性,不管它们的可见性如何。这对于确保所有属性都被包括在JSON中非常有用,尤其是当你需要在序列化时包括私有属性或其他非公共属性时。
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//ObjectMapper 将在序列化时包括类型信息,以便在反序列化时能够正确地还原对象的具体类型。
mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
serializer.setObjectMapper(mapper);
// 使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(serializer);
// Hash的key也采用StringRedisSerializer的序列化方式
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(serializer);
template.afterPropertiesSet();
return template;
}
}
Redisson分布式锁
可重入锁
@Slf4j
@Component
public class RedisLock {
@Autowired
private RedissonClient redissonClient;
/**
* 加锁
*
* @param lockName 锁
* @return Boolean
*/
public Boolean lock(String lockName) {
try {
RLock lock = redissonClient.getLock(lockName);
lock.lock();
log.info("Thread [{}] DistributedRedisLock lock [{}] success", Thread.currentThread().getName(), lockName);
return true;
} catch (Exception e) {
log.error("DistributedRedisLock lock [{}] Exception: {}", lockName, e.getMessage());
return false;
}
}
/**
* 加锁
*
* @param lockName 锁
* @return Boolean
*/
public Boolean lock(long leaseTime, TimeUnit timeUnit, String lockName) {
try {
RLock lock = redissonClient.getLock(lockName);
//leaseTime 秒钟自动解锁,自动解锁时间一定要大于业务执行时间
lock.lock(leaseTime, timeUnit);
log.info("Thread [{}] DistributedRedisLock lock [{}] success", Thread.currentThread().getName(), lockName);
return true;
} catch (Exception e) {
log.error("DistributedRedisLock lock [{}] Exception: {}", lockName, e.getMessage());
return false;
}
}
/**
* 加锁
*
* @param lockName 锁
* @return Boolean
*/
public Boolean tryLock(String lockName) {
try {
RLock lock = redissonClient.getLock(lockName);
boolean b = lock.tryLock();
log.info("Thread [{}] DistributedRedisLock lock [{}] {}", Thread.currentThread().getName(), lockName, b);
return b;
} catch (Exception e) {
log.error("DistributedRedisLock lock [{}] Exception: {}", lockName, e.getMessage());
return false;
}
}
/**
* 加锁
*
* @param lockName 锁
* @return Boolean
*/
public Boolean tryLock(long waitTime, long leaseTime, TimeUnit timeUnit, String lockName) {
try {
RLock lock = redissonClient.getLock(lockName);
//尝试加锁,最多等待 waitTime 秒,上锁以后 leaseTime 秒自动解锁
boolean b = lock.tryLock(waitTime, leaseTime, timeUnit);
log.info("Thread [{}] DistributedRedisLock tryLock [{}] {}", Thread.currentThread().getName(), lockName, b);
return b;
} catch (Exception e) {
log.error("DistributedRedisLock tryLock [{}] Exception: {}", lockName, e.getMessage());
return false;
}
}
/**
* 释放锁
*
* @param lockName 锁
* @return Boolean
*/
public Boolean unlock(String lockName) {
try {
RLock lock = redissonClient.getLock(lockName);
if (lock.isLocked()) {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
log.info("Thread [{}] DistributedRedisLock unlock [{}] success", Thread.currentThread().getName(), lockName);
}
}
return true;
} catch (Exception e) {
log.error("DistributedRedisLock unlock [{}] Exception: {}", lockName, e.getMessage());
return false;
}
}
/**
* 判断key是否被锁定
*
* @param lockName 锁
* @return Boolean
*/
public Boolean isLock(String lockName) {
try {
RLock lock = redissonClient.getLock(lockName);
boolean b = lock.isLocked();
log.info("Thread [{}] DistributedRedisLock isLock [{}] {}", Thread.currentThread().getName(), lockName, b);
return b;
} catch (Exception e) {
log.error("DistributedRedisLock isLock [{}] Exception: ", lockName, e);
return false;
}
}
}
联锁
RLock lock1 = redissonInstance1.getLock("lock1");
RLock lock2 = redissonInstance2.getLock("lock2");
RLock lock3 = redissonInstance3.getLock("lock3");
RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3);
//同时加锁:lock1 lock2 lock3
//所有的锁都上锁成功才算成功。
lock.lock();
...
lock.unlock();
红锁
RLock lock1 = redissonInstance1.getLock("lock1");
RLock lock2 = redissonInstance2.getLock("lock2");
RLock lock3 = redissonInstance3.getLock("lock3");
RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3);
//同时加锁:lock1 lock2 lock3
//红锁在大部分节点上加锁成功就算成功。
lock.lock();
...
lock.unlock();
看门狗
Redisson提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期,也就是说,如果一个拿到锁的线程一直没有完成逻辑,那么看门狗会帮助线程不断的延长锁超时时间,锁不会因为超时而被释放。
默认情况下,看门狗的续期时间是30s,也可以通过修改Config.lockWatchdogTimeout来另行指定。另外Redisson 还提供了可以指定leaseTime参数的加锁方法来指定加锁的时间。超过这个时间后锁便自动解开了,不会延长锁的有效期。