springboot设置集成RedisTemplate和Redisson,使用分布式锁案例 ...

河曲智叟  金牌会员 | 2024-6-28 14:08:46 | 来自手机 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 536|帖子 536|积分 1608

文章要点


  • 自定义设置属性类
  • 集成设置RedisTemplate
  • 集成设置分布式锁Redisson
  • 使用分布式锁简单实现超卖方案
1. 项目布局


2. 集成RedisTemplate和Redisson

添加依赖
依赖的版本与继续的spring-boot-starter-parent工程相对应,可写可不写
  1. <!--spring data redis & cache-->
  2.         <dependency>
  3.             <groupId>org.springframework.boot</groupId>
  4.             <artifactId>spring-boot-starter-data-redis</artifactId>
  5.         </dependency>
  6.         <!-- redis依赖commons-pool 这个依赖一定要添加 -->
  7.         <dependency>
  8.             <groupId>org.apache.commons</groupId>
  9.             <artifactId>commons-pool2</artifactId>
  10.         </dependency>
  11.         <!--redisson-->
  12.         <dependency>
  13.             <groupId>org.redisson</groupId>
  14.             <artifactId>redisson-spring-boot-starter</artifactId>
  15.             <version>3.15.6</version>
  16.         </dependency>
  17.         <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
  18.         <dependency>
  19.             <groupId>org.projectlombok</groupId>
  20.             <artifactId>lombok</artifactId>
  21.             <scope>provided</scope>
  22.         </dependency>
复制代码
大概图解
如上图,先设置application.yml设置Redis的各项属性包罗ip,端口,暗码。再注入。
  1. server:
  2.   port: 8080
  3. # Redis配置
  4. spring:
  5.   redis:
  6.     host: 192.168.200.131
  7.     port: 6379
  8.     password: root
复制代码
  1. // RedisConfigProperties.java
  2. @Data
  3. @ConfigurationProperties(prefix = "spring.redis")
  4. public class RedisConfigProperties {
  5.     private String host;
  6.     private int port;
  7.     private String password;
  8. }
  9. // RedisTemplateConfig.java
  10. @Configuration
  11. public class RedisTemplateConfig {
  12.     @Autowired
  13.     RedisConfigProperties redisConfigProperties;
  14.     @Bean
  15.     public RedisConnectionFactory redisConnectionFactory() {
  16.         RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(
  17.                 redisConfigProperties.getHost(), redisConfigProperties.getPort()
  18.         );
  19.         config.setPassword(redisConfigProperties.getPassword());
  20.         return new LettuceConnectionFactory(config);
  21.     }
  22.     @Bean
  23.     public RedisTemplate<String, Object> redisTemplate(){
  24.         RedisTemplate<String,Object> template = new RedisTemplate<>();
  25.         template.setConnectionFactory(redisConnectionFactory());
  26.         // 设置序列化器等其他配置
  27.         return template;
  28.     }
  29. }
  30. // RedissonConfig.java
  31. @Configuration
  32. @EnableConfigurationProperties({RedisConfigProperties.class})
  33. public class RedissonConfig {
  34.     @Autowired
  35.     RedisConfigProperties redisConfigProperties;
  36.     @Bean
  37.     public RedissonClient redissonClient(){
  38.         // 1. 创建配置文件
  39.         Config config = new Config();
  40.         // 2. 设置单节点服务器配置
  41.         config.useSingleServer().setAddress(
  42.                 "redis://"+redisConfigProperties.getHost()+":"+redisConfigProperties.getPort()
  43.         );
  44.         // 3. 如果Redis设置了密码,这里需要设置密码
  45.         config.useSingleServer().setPassword(redisConfigProperties.getPassword());
  46.         // 4. 创建RedissonClient实例
  47.         RedissonClient redisson = Redisson.create(config);
  48.         return redisson;
  49.     }
  50. }
复制代码
到这里,RedisTemplate和Redisson就已经集成好了,后续使用只必要注入就行。
例如
  1. @RestController
  2. @RequestMapping(value = "/order")
  3. public class OrderController {
  4.     @Autowired
  5.     //private RedisTemplate redisTemplate;
  6.     private StringRedisTemplate redisTemplate; //通常用这个StringRedisTemplate
  7.     @Autowired
  8.     private RedissonClient redissonClient;
  9.         ...
  10.         ...
  11. }
复制代码
3. 模拟分布式场景下超卖现象

OrderController
  1.         /***
  2.      * 抢单
  3.      */
  4.     @GetMapping(value = "/v1/{id}/{num}")
  5.     public String addv1(@PathVariable(value = "id")String id,@PathVariable("num")Long num) throws InterruptedException {
  6.         // 1.查询库存
  7.         int count = Integer.valueOf(redisTemplate.opsForValue().get(id));
  8.         System.out.println("剩余库存:"+count);
  9.         // 2.库存充足
  10.         if (count>=num){
  11.             //模拟操作
  12.             TimeUnit.SECONDS.sleep(5);
  13.             //递减库存
  14.             Long decrement = redisTemplate.opsForValue().decrement(id, num);
  15.             System.out.println("递减库存后剩余库存:"+decrement);
  16.             //其它操作 略
  17.             System.out.println("----添加订单了!");
  18.             return "下单成功";
  19.         }
  20.         //库存不足
  21.         else {
  22.             return "库存不足";
  23.         }
  24.     }
复制代码
复制一个端口为8081的设置,模拟分布式服务

启动两个服务

在Redis中设置一个键值对water:2,模拟水的库存为2.
欣赏器同时发送2个哀求,模拟有2个用户同时每人买2瓶水
http://127.0.0.1:8080/order/v1/water/2
http://127.0.0.1:8081/order/v1/water/2

出现超卖现象
4. 利用Redisson分布式锁,防止超卖

   关键代码
  1. RLock lock = redissonClient.getLock("mylock_" + id);
  2. lock.lock();   //自旋获取锁
  3. ...
  4. ...
  5. lock.unlock();
复制代码
首先记得set water 2
OrderController
  1.         /***
  2.      * 抢单,使用分布式锁
  3.      */
  4.     @GetMapping(value = "/{id}/{num}")
  5.     public String add(@PathVariable(value = "id")String id,@PathVariable("num")Long num) throws InterruptedException {
  6.         //对该商品加锁,加锁成功,则判断库存,避免多人同时判断某一个商品的库存
  7.         RLock lock = redissonClient.getLock("mylock_" + id);
  8.         lock.lock();   //自旋获取锁
  9.         System.out.println("获取了锁!"+lock.getName());
  10.         try {
  11.             // 1.查询库存
  12.             int count = Integer.valueOf(redisTemplate.opsForValue().get(id));
  13.             System.out.println("剩余库存:"+count);
  14.             // 2.库存充足
  15.             if (count>=num){
  16.                 //模拟操作
  17.                 TimeUnit.SECONDS.sleep(5);
  18.                 //递减库存
  19.                 Long decrement = redisTemplate.opsForValue().decrement(id, num);
  20.                 System.out.println("递减库存后剩余库存:"+decrement);
  21.                 //其它操作 略
  22.                 System.out.println("----添加订单了!");
  23.                 return "下单成功";
  24.             }
  25.             //库存不足
  26.             else {
  27.                 return "库存不足";
  28.             }
  29.         } finally {
  30.             //释放锁
  31.             System.out.println("释放了锁!"+lock.getName());
  32.             lock.unlock();
  33.         }
  34.     }
复制代码
启动2个服务,欣赏器同时发送2个哀求
http://127.0.0.1:8080/order/water/2
http://127.0.0.1:8081/order/water/2

防止了超卖现象

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

河曲智叟

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表