首页 > 数据库 >SpringBoot | Redis序列化与分布式锁

SpringBoot | Redis序列化与分布式锁

时间:2023-09-27 09:45:28浏览次数:36  
标签:Exception return SpringBoot getLock lock Redis lockName 序列化 log

欢迎参观我的博客,一个Vue 与 SpringBoot结合的产物:https://poetize.cn

原文链接: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参数的加锁方法来指定加锁的时间。超过这个时间后锁便自动解开了,不会延长锁的有效期。

标签:Exception,return,SpringBoot,getLock,lock,Redis,lockName,序列化,log
From: https://www.cnblogs.com/loveer/p/17731943.html

相关文章

  • SpringBoot | Jackson序列化
    欢迎参观我的博客,一个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:/......
  • Redis 主从复制、哨兵模式、群集模式
    Redis主从复制、哨兵模式、群集模式目录1.Redis的2种持久化方式2.Redis优化3.Redis主从复制的原理3.1配置文件3.2Redis主从复制4.Redis哨兵模式4.1哨兵机制4.2哨兵模式的作用4.3哨兵结构4.4哨兵模式配置1.Redis的2种持久化方式RDB持久化定时把red......
  • Redis之Java客户端连接
    Spring整合Redis使用Lettuce框架访问RedisprivatestaticRedisCommands<String,String>createRedisCommands(){RedisURI.Builderbuilder=RedisURI.Builder.redis("",6379);builder.withPassword("test123").withDatabase(1);Redis......
  • 新手指引:前后端分离的springboot + mysql + vue实战案例
    案例说明:使用springboot+mysql+vue实现前后端分离的用户查询功能。1、mysql:创建test数据库->创建user数据表->创建模拟数据;2、springboot:配置mysql->使用mybatis操作mysql数据库->接口开发;3、vue:使用axios访问接口->user数据展示;1、mysql数据库1.1、安......
  • docker-compose安装Redis
    一、单机版本1、docker-composeversion:'3'services:redis:image:redis:5.0restart:alwaysprivileged:truecontainer_name:redis-javaports:-6379:6379volumes:-/var/docker/server/redis/redis.conf:/etc/redis......
  • Redis内存碎片:深度解析与优化策略
    本文已收录至GitHub,推荐阅读......
  • Redis系列23:性能优化指南
    Redis系列1:深刻理解高性能Redis的本质Redis系列2:数据持久化提高可用性Redis系列3:高可用之主从架构Redis系列4:高可用之Sentinel(哨兵模式)Redis系列5:深入分析Cluster集群模式追求性能极致:Redis6.0的多线程模型追求性能极致:客户端缓存带来的革命Redis系列8:Bitmap实现亿万级......
  • 使用HHDBCS管理Redis
    Redis是一款内存高速缓存数据库,可用于缓存,事件发布或订阅,高速队列等场景。因此,根据需要,HHDBCS在主页设置了“发布窗口”及“订阅窗口”。1连接redis打开HHDBCS,在数据库类型中选择Redis,填入相关信息,点击“登陆”即可。2订阅功能点击“订阅窗口”,在弹出框中填入信息,点击订......
  • Mac故障排查系列:redis删除key报错MISCONF Redis is configured to save RDB snapshots
    背景:Mac下使用AnotherRedisDesktopManager客户端,删除key,遇到报错:MISCONFRedisisconfiguredtosaveRDBsnapshots,butit'scurrentlyunabletopersisttodisk.Commandsthatmaymodifythedatasetaredisabled,becausethisinstanceisconfiguredtoreporte......
  • springboot大文件上传、分片上传、断点续传、秒传的实现
    对于大文件的处理,无论是用户端还是服务端,如果一次性进行读取发送、接收都是不可取,很容易导致内存问题。所以对于大文件上传,采用切块分段上传,从上传的效率来看,利用多线程并发上传能够达到最大效率。 本文是基于springboot+vue实现的文件上传,本文主要介绍服务端实现文件上传的......