• Redis - Redisson


    目录

    可重入锁

     MultiLock: 连锁

     代码实现:

    布隆过滤器


    Redis实现的分布式锁还存在一下问题:

     Redisson可以全部解决以上问题

    1. Redisson获取的锁是可重入的锁

    RLock lock = redissonClient.getLock("lock:order"); 

    2. waitTime为重试时间,leaseTime为持有的超时时间

    lock.tryLock(long waitTime, long leaseTime, TimeUnit unit)

    3.不设置leaseTime,可以解决超时释放带来的并发安全隐患

    4.解决主从一致性问题,采用连锁,多个节点都为主节点。同时获取全部节点的锁。

     引入依赖

    1. <dependency>
    2. <groupId>org.redissongroupId>
    3. <artifactId>redissonartifactId>
    4. <version>3.17.5version>
    5. dependency>

    添加配置

    1. @Configuration
    2. public class RedissonConfig {
    3. @Bean
    4. public RedissonClient redissonClient() {
    5. //配置
    6. Config config = new Config();
    7. //添加Redis地址,这里添加单点地址,也可以使用config.useClusterServers()添加集群地址
    8. config.useSingleServer().setAddress("redis://192.168.99.100:56379").setPassword("123321");
    9. //创建Redis对象
    10. return Redisson.create(config);
    11. }
    12. }

    使用Redisson提供的分布式锁

    1. @Service
    2. public class DistributePayImpl implements SinglePay {
    3. @Autowired
    4. SimpleRedisLock simpleRedisLock;
    5. @Autowired
    6. RedissonClient redissonClient;
    7. public void buyOrder(Long userId) {
    8. buyOrder_RedissionLock(userId);
    9. }
    10. private void buyOrder_RedissionLock(Long userId){
    11. String lockKey = "lock:order:" + userId;
    12. //使用Redisson获取锁
    13. RLock lock = redissonClient.getLock(lockKey);
    14. //tryLock无参为默认值,只尝试一次,获取不到就不等了,持有锁的时间为30s,超过自动释放
    15. boolean isLock = lock.tryLock();
    16. if (!isLock) {
    17. //获取锁失败,返回错误或重试
    18. //"一人只能下一单"
    19. return;
    20. }
    21. try {
    22. SinglePay proxy = (SinglePay) AopContext.currentProxy();
    23. proxy.createOrder(userId);
    24. } finally {
    25. lock.unlock();
    26. }
    27. }
    28. @Transactional
    29. public String createOrder(Long userId) {
    30. //查询数据库order中userId是否存在记录,存在则不让购买
    31. int count = queryOrderCount(userId);
    32. if (count > 0) {
    33. //已买过购买失败
    34. return "fail";
    35. }
    36. boolean success = order_count(userId);
    37. if (!success) {
    38. return "库存不足";
    39. }
    40. saveOrder(userId);
    41. return "成功";
    42. // }
    43. }
    44. private void saveOrder(Long userId) {
    45. //模拟提交订单插入数据库
    46. //insert into order values(userId.....);
    47. }
    48. private boolean order_count(Long userId) {
    49. //修改库存
    50. //update order_count set count = count -1 where userId =? and count >0;
    51. return true;
    52. }
    53. private int queryOrderCount(Long userId) {
    54. //模拟查询数据库
    55. //select count(*) from order where userId = ?
    56. return 0;
    57. }
    58. }

    可重入锁

    redissonClient.getLock(key)获得锁为可冲入锁,在redis中存储的类型为hash类型
    1. @Slf4j
    2. @SpringBootTest
    3. class RedissonTests {
    4. @Autowired
    5. private RedissonClient redissonClient;
    6. private RLock lock;
    7. @BeforeEach
    8. void setUp() {
    9. lock = redissonClient.getLock("lock:order");
    10. }
    11. @Test
    12. void testString() {
    13. boolean isLock = lock.tryLock();
    14. if (!isLock) {
    15. log.error("获取锁失败.....1");
    16. return;
    17. }
    18. try {
    19. log.info("获取锁成功......1");
    20. method2();
    21. log.info("开始执行业务......1");
    22. } finally {
    23. log.info("准备释放锁......1");
    24. lock.unlock();
    25. }
    26. }
    27. private void method2() {
    28. boolean isLock = lock.tryLock();
    29. if (!isLock) {
    30. log.error("获取锁失败.....2");
    31. return;
    32. }
    33. try {
    34. log.info("获取锁成功.....2");
    35. log.info("开始执行业务......2");
    36. } finally {
    37. log.info("准备释放锁......2");
    38. lock.unlock();
    39. }
    40. }
    41. }

     根据上图可以发现,同一个线程可以多次获取锁,value值会增加。key的UUID和线程一一对应

     

     MultiLock: 连锁

    同时获取多个Redis节点的锁,只有全部获取到才算是获取锁成功,否则视为失败 

     代码实现:

    1. //连接多个Redis节点
    2. @Configuration
    3. public class RedissonConfig {
    4. @Bean
    5. public RedissonClient redissonClient() {
    6. //配置
    7. Config config = new Config();
    8. //添加Redis地址,这里添加单点地址,也可以使用config.useClusterServers()添加集群地址
    9. config.useSingleServer().setAddress("redis://192.168.99.100:56379").setPassword("123321");
    10. //创建Redis对象
    11. return Redisson.create(config);
    12. }
    13. @Bean
    14. public RedissonClient redissonClient2() {
    15. //配置
    16. Config config = new Config();
    17. //添加Redis地址,这里添加单点地址,也可以使用config.useClusterServers()添加集群地址
    18. config.useSingleServer().setAddress("redis://192.168.99.100:56378").setPassword("123321");
    19. //创建Redis对象
    20. return Redisson.create(config);
    21. }
    22. @Bean
    23. public RedissonClient redissonClient3() {
    24. //配置
    25. Config config = new Config();
    26. //添加Redis地址,这里添加单点地址,也可以使用config.useClusterServers()添加集群地址
    27. config.useSingleServer().setAddress("redis://192.168.99.100:56377").setPassword("123321");
    28. //创建Redis对象
    29. return Redisson.create(config);
    30. }
    31. }
    32. @Slf4j
    33. @SpringBootTest
    34. class RedissonTests {
    35. @Autowired
    36. private RedissonClient redissonClient;
    37. @Autowired
    38. private RedissonClient redissonClient2;
    39. @Autowired
    40. private RedissonClient redissonClient3;
    41. private RLock lock;
    42. @BeforeEach
    43. void setUp() {
    44. RLock lock1 = redissonClient.getLock("lock:order");
    45. RLock lock2 = redissonClient2.getLock("lock:order");
    46. RLock lock3 = redissonClient3.getLock("lock:order");
    47. //从多把锁中获取的最终的lock
    48. lock = redissonClient.getMultiLock(lock1,lock2,lock3);
    49. }
    50. @Test
    51. void testString() {
    52. boolean isLock = lock.tryLock();
    53. if (!isLock) {
    54. log.error("获取锁失败.....1");
    55. return;
    56. }
    57. try {
    58. log.info("获取锁成功......1");
    59. method2();
    60. log.info("开始执行业务......1");
    61. } finally {
    62. log.info("准备释放锁......1");
    63. lock.unlock();
    64. }
    65. }
    66. private void method2() {
    67. boolean isLock = lock.tryLock();
    68. if (!isLock) {
    69. log.error("获取锁失败.....2");
    70. return;
    71. }
    72. try {
    73. log.info("获取锁成功.....2");
    74. log.info("开始执行业务......2");
    75. } finally {
    76. log.info("准备释放锁......2");
    77. lock.unlock();
    78. }
    79. }
    80. }

    RLock lock = redissonClient.getMultiLock(lock1,lock2,lock3);

    根绝多把锁获取最总错做的RLock对象,当tryLock成功时,会在所有的Redis的节点中存在key =lock:order的记录

    布隆过滤器

    1. Config config = new Config();
    2. //添加Redis地址,这里添加单点地址,也可以使用config.useClusterServers()添加集群地址
    3. config.useSingleServer().setAddress("redis://192.168.99.100:56379").setPassword("123321");
    4. //创建Redis对象
    5. Redisson redisson = Redisson.create(config);
    6. RBloomFilter bloomFilter = redisson.getBloomFilter("product:bloom");
    7. //初始化布隆过滤器:预计元素1000000L,误判率为1%
    8. bloomFilter.tryInit(1000000L,0.01);
    9. bloomFilter.add("1");//添加数据
    10. //判断在布隆过滤器中是否存在
    11. System.out.println(bloomFilter.contains("1"));//输出true
    12. System.out.println(bloomFilter.contains("8888"));输出false

  • 相关阅读:
    跑通Kaldi中的例子LibriSpeech
    基于SSH框架的学生信息管理系统
    Nginx安装与虚拟主机配置shell脚本
    39.JavaScript中Promise的基本概念、使用方法,回调地狱规避、链式编程
    html网页制作期末大作业-网上花店商城html+css+javascript
    数据结构复习笔记6.2:图的存储和遍历
    基本通信设备
    数据库分库分表的原则
    CNN-generated images are surprisingly easy to spot... for now
    LeetCode 268. 丢失的数字
  • 原文地址:https://blog.csdn.net/qq_33753147/article/details/126429159