• Redisson 集成SpringBoot 详解


    一、引入依赖

    1. <dependency>
    2. <groupId>org.redisson</groupId>
    3. <artifactId>redisson-spring-boot-starter</artifactId>
    4. <version>3.23.5</version>
    5. </dependency>

    redison-spring-boot-starter依赖于与最新版本的spring-boot兼容的redison-spring数据模块。降级redison弹簧数据模块(如有必要),以支持以前的spring Boot版本:

    redisson-spring-data module nameSpring Boot version
    redisson-spring-data-161.3.y
    redisson-spring-data-171.4.y
    redisson-spring-data-181.5.y
    redisson-spring-data-2x2.x.y
    redisson-spring-data-3x3.x.y

    二、添加配置文件

    使用 common Spring Boot 3.x+ settings:

    1. spring:
    2. data:
    3. redis:
    4. database:
    5. host:
    6. port:
    7. password:
    8. ssl:
    9. timeout:
    10. connectTimeout:
    11. clientName:
    12. cluster:
    13. nodes:
    14. sentinel:
    15. master:
    16. nodes:

    使用common Spring Boot up to 2.7.x settings:

    1. spring:
    2. redis:
    3. database:
    4. host:
    5. port:
    6. password:
    7. ssl:
    8. timeout:
    9. connectTimeout:
    10. clientName:
    11. cluster:
    12. nodes:
    13. sentinel:
    14. master:
    15. nodes:

     配置redision属性(application.yaml):

    1. spring:
    2. redis:
    3. redisson:
    4. config: |
    5. clusterServersConfig:
    6. idleConnectionTimeout: 10000
    7. connectTimeout: 10000
    8. timeout: 3000
    9. retryAttempts: 3
    10. retryInterval: 1500
    11. failedSlaveReconnectionInterval: 3000
    12. failedSlaveCheckInterval: 60000
    13. password: null
    14. subscriptionsPerConnection: 5
    15. clientName: null
    16. loadBalancer: !<org.redisson.connection.balancer.RoundRobinLoadBalancer> {}
    17. subscriptionConnectionMinimumIdleSize: 1
    18. subscriptionConnectionPoolSize: 50
    19. slaveConnectionMinimumIdleSize: 24
    20. slaveConnectionPoolSize: 64
    21. masterConnectionMinimumIdleSize: 24
    22. masterConnectionPoolSize: 64
    23. readMode: "SLAVE"
    24. subscriptionMode: "SLAVE"
    25. nodeAddresses:
    26. - "redis://127.0.0.1:7004"
    27. - "redis://127.0.0.1:7001"
    28. - "redis://127.0.0.1:7000"
    29. scanInterval: 1000
    30. pingConnectionInterval: 0
    31. keepAlive: false
    32. tcpNoDelay: false
    33. threads: 16
    34. nettyThreads: 32
    35. codec: !<org.redisson.codec.Kryo5Codec> {}
    36. transportMode: "NIO"

    三、使用 RedissonClient

    除了常用的 StringRedisTemplate 外,我们还可以注入如下由 Redisson 提供的 Bean:

    • RedissonClient
    • RedissonRxClient(响应式)
    • RedissonReactiveClient(响应式)
    • RedisTemplate
    • ReactiveRedisTemplate(响应式)

    四、接下来,我们使用 RedissonClient 来实现一个分布式锁,以进行测试:

    1. import org.junit.jupiter.api.Test;
    2. import org.redisson.api.RedissonClient;
    3. import java.util.concurrent.CountDownLatch;
    4. import java.util.concurrent.locks.Lock;
    5. import org.slf4j.Logger;
    6. import org.slf4j.LoggerFactory;
    7. import org.springframework.beans.factory.annotation.Autowired;
    8. import org.springframework.boot.test.context.SpringBootTest;
    9. import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
    10. @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
    11. public class Application {
    12. static final Logger logger = LoggerFactory.getLogger(DemoApplicationTests.class);
    13. // 注入 RedissonClient
    14. @Autowired
    15. RedissonClient redissonClient;
    16. // 计数器
    17. private int count;
    18. @Test
    19. public void LockOp throws InterruptedException {
    20. CountDownLatch countDownLatch = new CountDownLatch(1000);
    21. for (int i = 0; i < 1000; i++) {
    22. new Thread(() -> {
    23. // 每个线程都创建自己的锁对象
    24. // 这是基于 Redis 实现的分布式锁
    25. Lock lock = this.redissonClient.getLock("counterLock");
    26. try {
    27. // 上锁
    28. lock.lock();
    29. // 计数器自增 1
    30. this.count = this.count + 1;
    31. } finally {
    32. // 释放锁
    33. lock.unlock();
    34. }
    35. countDownLatch.countDown();
    36. }).start();
    37. }
    38. countDownLatch.await();
    39. logger.info("count = {}", this.count);
    40. }

    如上。我们在测试类中注入了 RedissonClient Bean,并且定义了一个 count 属性。在测试方法中,启动 1000 个线程对 count 属性进行 +1 操作。其中,每个线程都通过 RedissonClient 获取分布式锁来控制对变量的并发修改。

    运行测试,输出的日志如下:

    INFO 4840 --- [           main] c.s.demo.test.DemoApplicationTests       : count = 1000
    

    最后的结果是 1000,分布式锁生效。

    五、 复杂多维对象结构和对象引用的支持

    Redisson突破了Redis数据结构维度的限制,通过一个特殊引用对象的帮助,Redisson允许以任意的组合方式构建多维度的复杂对象结构,实现了对象之间的类似传统数据库里的关联关系。使用范例如下:

    1. RMap<RSet<RList>, RList<RMap>> map = redisson.getMap("myMap");
    2. RSet<RList> set = redisson.getSet("mySet");
    3. RList<RMap> list = redisson.getList("myList");
    4. map.put(set, list);
    5. // 在特殊引用对象的帮助下,我们甚至可以构建一个循环引用,这是通过普通序列化方式实现不了的。
    6. set.add(list);
    7. list.add(map);

    可能您已经注意到了,在map包含的元素发生改变以后,我们无需再次“保存/持久”这些对象。因为map对象所记录的并不是序列化以后的值,而是元素对象的引用。这让Redisson提供的对象在使用方法上,与普通Java对象的使用方法一致。从而让Redis成为内存的一部分,而不仅仅是一个储存空间。

    以上范例中,一共创建了三个Redis数据结构:一个Redis HASH,一个Redis SET和一个Redis LIST。

    六、 命令的批量执行

    多个连续命令可以通过RBatch对象在一次网络会话请求里合并发送,这样省去了产生多个请求消耗的时间和资源。这在Redis中叫做管道。

    用户可以通过以下方式调整通过管道方式发送命令的方式:

    1. BatchOptions options = BatchOptions.defaults()
    2. // 指定执行模式
    3. //
    4. // ExecutionMode.REDIS_READ_ATOMIC - 所有命令缓存在Redis节点中,以原子性事务的方式执行。
    5. //
    6. // ExecutionMode.REDIS_WRITE_ATOMIC - 所有命令缓存在Redis节点中,以原子性事务的方式执行。
    7. //
    8. // ExecutionMode.IN_MEMORY - 所有命令缓存在Redisson本机内存中统一发送,但逐一执行(非事务)。默认模式。
    9. //
    10. // ExecutionMode.IN_MEMORY_ATOMIC - 所有命令缓存在Redisson本机内存中统一发送,并以原子性事务的方式执行。
    11. //
    12. .executionMode(ExecutionMode.IN_MEMORY)
    13. // 告知Redis不用返回结果(可以减少网络用量)
    14. .skipResult()
    15. // 将写入操作同步到从节点
    16. // 同步到2个从节点,等待时间为1秒钟
    17. .syncSlaves(2, 1, TimeUnit.SECONDS)
    18. // 处理结果超时为2秒钟
    19. .responseTimeout(2, TimeUnit.SECONDS)
    20. // 命令重试等待间隔时间为2秒钟
    21. .retryInterval(2, TimeUnit.SECONDS);
    22. // 命令重试次数。仅适用于未发送成功的命令
    23. .retryAttempts(4);

    使用方式如下:

    1. RBatch batch = redisson.createBatch();
    2. batch.getMap("test").fastPutAsync("1", "2");
    3. batch.getMap("test").fastPutAsync("2", "3");
    4. batch.getMap("test").putAsync("2", "5");
    5. batch.getAtomicLongAsync("counter").incrementAndGetAsync();
    6. batch.getAtomicLongAsync("counter").incrementAndGetAsync();
    7. BatchResult res = batch.execute();
    8. // 或者
    9. Future<BatchResult> asyncRes = batch.executeAsync();
    10. List<?> response = res.getResponses();
    11. res.getSyncedSlaves();

    在集群模式下,所有的命令会按各个槽所在的节点,筛选分配到各个节点并同时发送。每个节点返回的结果将会汇总到最终的结果列表里。

    七、Redisson事务

    Redisson为RMap、RMapCache、RLocalCachedMap、RSet、RSetCache和RBucket这样的对象提供了具有ACID属性的事务功能。Redisson事务通过分布式锁保证了连续写入的原子性,同时在内部通过操作指令队列实现了Redis原本没有的提交与滚回功能。当提交与滚回遇到问题的时候,将通过org.redisson.transaction.TransactionException告知用户。

    目前支持的环境如下: SINGLE, MASTER/SLAVE, SENTINEL, ELASTICACHE REPLICATED, AZURE CACHE, RLEC。

    Redisson事务支持的事务隔离等级为: READ_COMMITTED,即仅读取提交后的结果。

    另见 Spring事务管理器 和本章 XA事务(XA Transactions)。

    以下选项可以用来配置事务属性:

    1. TransactionOptions options = TransactionOptions.defaults()
    2. // 设置参与本次事务的主节点与其从节点同步的超时时间。
    3. // 默认值是5秒。
    4. .syncSlavesTimeout(5, TimeUnit.SECONDS)
    5. // 处理结果超时。
    6. // 默认值是3秒。
    7. .responseTimeout(3, TimeUnit.SECONDS)
    8. // 命令重试等待间隔时间。仅适用于未发送成功的命令。
    9. // 默认值是1.5秒。
    10. .retryInterval(2, TimeUnit.SECONDS)
    11. // 命令重试次数。仅适用于未发送成功的命令。
    12. // 默认值是3次。
    13. .retryAttempts(3)
    14. // 事务超时时间。如果规定时间内没有提交该事务则自动滚回。
    15. // 默认值是5秒。
    16. .timeout(5, TimeUnit.SECONDS);

    代码范例:

    1. RTransaction transaction = redisson.createTransaction(TransactionOptions.defaults());
    2. RMap<String, String> map = transaction.getMap("myMap");
    3. map.put("1", "2");
    4. String value = map.get("3");
    5. RSet<String> set = transaction.getSet("mySet")
    6. set.add(value);
    7. try {
    8. transaction.commit();
    9. } catch(TransactionException e) {
    10. transaction.rollback();
    11. }

    八、XA事务(XA Transactions)

    Redisson提供了XAResource标准的实现。该实现可用于JTA事务中。

    另见本章Redisson事务和Spring事务管理器。

    该功能仅适用于Redisson PRO版本

    代码范例:

    1. // Transaction对象可以从所有兼容JTA接口的事务管理器中获取。
    2. Transaction globalTransaction = transactionManager.getTransaction();
    3. RXAResource xaResource = redisson.getXAResource();
    4. globalTransaction.enlistResource(xaResource);
    5. RTransaction transaction = xaResource.getTransaction();
    6. RBucket<String> bucket = transaction.getBucket("myBucket");
    7. bucket.set("simple");
    8. RMap<String, String> map = transaction.getMap("myMap");
    9. map.put("myKey", "myValue");
    10. transactionManager.commit();

  • 相关阅读:
    【houdini vex】时间偏移
    两个线程交替执行的几种方式
    入门JavaWeb之 Response 下载文件
    k8s集群StatefulSets的Pod优雅调度问题思考?
    从0搭建Vue3组件库(四): 如何开发一个组件
    IDEA自定义Maven仓库
    ffplay视频播放原理分析
    Nacos学习笔记
    【云原生】springcloud08——Ribbon负载均衡调用
    十大经典排序算法
  • 原文地址:https://blog.csdn.net/leesinbad/article/details/133526150