• Springboot实战:redisson分布式缓存、分布式锁详细教程(附git源码)


    Springboot-cli 开发脚手架系列



    简介

    Redisson在基于NIO的Netty框架上,充分的利用了Redis键值数据库提供的一系列优势,在Java实用工具包中常用接口的基础上,为使用者提供了一系列具有分布式特性的常用工具类。

    优势:

    • 自带分布式锁
    • watch dog自动延期机制,无需手动对锁时间进行续期
    • 缓存存储结构丰富
    • 支持队列、延时队列
    • 支持Topic机制

    1. 环境

    • 依赖pom.xml
        <dependency>
                <groupId>org.redisson</groupId>
                <artifactId>redisson</artifactId>
                <version>3.14.0</version>
            </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • yml配置(简配版)
    # redis 配置
    redisson:
      # 是否集群
      cluster: false
      # 数组格式,参考<yml配置数组>,若开启集群模式,最少配置3个节点
      address:
        - redis://192.168.41.128:6379
      # 连接超时时间
      connect-timeout: 3
      # 密码
      password: 123456
      # redis数据库序号,只有单机模式下生效
      database: 0
      # 传输模式 linux上开启会有更高的性能
      use-epoll: false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2. 客户端配置

    • 读取yml配置
    /**
     * redisson yml配置
     * @author : qiDing
     */
    @Data
    @Accessors(chain = true)
    @Configuration
    @ConfigurationProperties(prefix = RedissonProperties.PREFIX)
    public class RedissonProperties {
    
        public static final String PREFIX = "redisson";
        /**
         * 连接超时,单位:毫秒
         */
        private Integer connectTimeout;
    
        /**
         * 密码
         */
        private String password;
    
        /**
         * 服务器地址
         */
        private String[] address;
    
        /**
         * 数据库序号,只有单机模式下生效
         */
        private Integer database;
    
        /**
         * 传输模式 linux上开启会有更高的性能
         */
        private Boolean useEpoll;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 配置redisson客户端
    /**
     * Redisson 核心配置
     * 更多配置参考 https://github.com/redisson/redisson/wiki/2.-Configuration
     * @author ding
     */
    @Configuration
    @ComponentScan
    @EnableCaching
    @RequiredArgsConstructor
    public class RedissonConfig {
    
        @Resource
        private RedissonProperties redissonProperties;
    
        /**
         * 单机配置
         */
        @Bean
        @ConditionalOnExpression("'${redisson.cluster}' == 'false'")
        public RedissonClient getRedisson() {
            Config config = new Config();
            config.setTransportMode(redissonProperties.getUseEpoll() ? TransportMode.EPOLL : TransportMode.NIO)
                    .setCodec(JsonJacksonCodec.INSTANCE)
                    .useSingleServer()
                    .setPassword(redissonProperties.getPassword())
                    .setDatabase(redissonProperties.getDatabase())
                    .setAddress(redissonProperties.getAddress()[0]);
            return Redisson.create(config);
        }
    
    
        /**
         * 集群配置
         */
        @Bean
        @ConditionalOnExpression("'${redisson.cluster}' == 'true'")
        public RedissonClient getClusterRedisson() {
            Config config = new Config();
            config.setTransportMode(redissonProperties.getUseEpoll() ? TransportMode.EPOLL : TransportMode.NIO)
                    .setCodec(JsonJacksonCodec.INSTANCE)
                    .useClusterServers()
                    // 集群状态扫描间隔时间,单位是毫秒
                    .setScanInterval(3000)
                    .setPassword(redissonProperties.getPassword())
                    .addNodeAddress(redissonProperties.getAddress());
            return Redisson.create(config);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    3. 模拟产品业务实战

    • 编写业务缓存类ProductCache
    @Component
    @RequiredArgsConstructor
    @Slf4j
    public class ProductCache {
    
        private final RedissonClient redissonClient;
    
        /**
         * 存储桶形式存放
         */
        public void setBucket(String key, Product product) {
            redissonClient.getBucket(key).set(product);
        }
    
        /**
         * 存储桶形式存放
         *
         * @param timeout 超时时间
         */
        public void setBucket(String key, Product product, long timeout) {
            redissonClient.getBucket(key).set(product, timeout, TimeUnit.SECONDS);
        }
    
        /**
         * 获取值
         */
        public Product getBucket(String key) {
            RBucket<Product> product = redissonClient.getBucket(key);
            return product.get();
        }
    
        /**
         * 以map的形式存放
         *
         * @param timeout 超时时间
         */
        public void putMapCache(Long productId, Product product, long timeout) {
            redissonClient.getMapCache("productMap").put(productId, product, timeout, TimeUnit.SECONDS);
        }
    
        /**
         * 获取map中的值
         */
        public Product getMapByKey(Long productId) {
            RMapCache<Long, Product> productMap = redissonClient.getMapCache("productMap");
            return productMap.get(productId);
        }
    
    
        /**
         * 以set的形式存放
         *
         * @param timeout 超时时间
         */
        public void addSetCache(Product product, long timeout) {
            redissonClient.getSetCache("productSet").add(product, timeout, TimeUnit.SECONDS);
        }
    
        /**
         * 打印set集合
         */
        public void printSet() {
            RSetCache<Product> product = redissonClient.getSetCache("product");
            product.iterator()
                    .forEachRemaining(p -> log.info("读取到:{}", p));
        }
    
        /**
         * 实现分布式锁
         */
        public void lockTest() {
            RLock lock = redissonClient.getLock("productId");
            lock.lock();
            try {
                // 执行业务代码
                log.info("执行业务代码");
            } finally {
                lock.unlock();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    4. 效果演示

    • 编写测试类DomeApplicationTests
    @SpringBootTest
    @Slf4j
    class DomeApplicationTests {
    
        @Autowired
        ProductCache productCache;
    
        @Test
        void setBucket() {
            Product product = new Product()
                    .setProductId(1L)
                    .setProductName("F12战斗鸡")
                    .setCreatedDate(new Date());
            productCache.setBucket("key001", product);
        }
    
        @Test
        void getBucket() {
            Product p = productCache.getBucket("key001");
            log.info("获取到数据:{}", p);
        }
    
        @Test
        void putMapCache() {
            for (int i = 0; i < 10; i++) {
                Product product = new Product()
                        .setProductId(1L + i)
                        .setProductName("F12战斗鸡")
                        .setCreatedDate(new Date());
                productCache.putMapCache(1L + i, product, 3600);
            }
        }
    
        @Test
        void getMapByKey() {
            Product p = productCache.getMapByKey(1L);
            log.info("获取到数据:{}", p);
        }
    
        @Test
        void addSet() {
            for (int i = 0; i < 10; i++) {
                Product product = new Product()
                        .setProductId(1L + i)
                        .setProductName("F12战斗鸡")
                        .setCreatedDate(new Date());
                productCache.addSetCache(product, 3600);
            }
        }
    
        @Test
        void printSet() {
            productCache.printSet();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 存储桶形式存储
      在这里插入图片描述
    • MapCache形式存储
      在这里插入图片描述
      这里可以发现我们明明是设置了有效期,但这里TTL为什么是-1呢?通过观察我们可以发现,缓存中多了redisson_timeout_set这个key,其实这个就是redission用来计算key过期时间的。
      在这里插入图片描述
    • SetCache形式存储
      在这里插入图片描述

    5. 分布式锁

    • 利用该框架暴露出来的接口,获取锁对象:redission.getLock("xxx")
    • 加锁:lock .lock()
    • 解锁:lock.unlock()
        /**
         * 实现分布式锁
         */
        public void lockTest() {
            RLock lock = redissonClient.getLock("productId");
            lock.lock();
            try {
                // 执行业务代码
                log.info("执行业务代码");
            } finally {
                lock.unlock();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    6. 源码分享

    本项目已收录
    Springboot、SpringCloud全家桶教程+源码,各种常用框架使用案例都有哦,具备完善的文档,致力于让开发者快速搭建基础环境并让应用跑起来,并提供丰富的使用示例供使用者参考,快来看看吧。

  • 相关阅读:
    系列十、你说你做过JVM调优和参数配置,请问如何盘点JVM系统的默认值?
    学习笔记-Power-Linux
    A1S65B-S1 A1S61PN A1SJ51T64 机器人的优点和缺点
    14:00面试,14:06就出来了,问的问题有点变态。。。
    gif动态图片如何做?两个方法教你在线制作gif
    VTP协议
    Mysql第二篇---InnoDB数据存储结构
    jQuery中遍历元素,创建元素,添加元素,删除元素汇总
    第十一章:Java对象内存布局和对象头
    c语言---指针进阶(1)
  • 原文地址:https://blog.csdn.net/qq_42411805/article/details/125023697