文章要点
- 自定义设置属性类
- 集成设置RedisTemplate
- 集成设置分布式锁Redisson
- 使用分布式锁简单实现超卖方案
1. 项目布局
2. 集成RedisTemplate和Redisson
添加依赖
依赖的版本与继续的spring-boot-starter-parent工程相对应,可写可不写
- <!--spring data redis & cache-->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-redis</artifactId>
- </dependency>
- <!-- redis依赖commons-pool 这个依赖一定要添加 -->
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-pool2</artifactId>
- </dependency>
- <!--redisson-->
- <dependency>
- <groupId>org.redisson</groupId>
- <artifactId>redisson-spring-boot-starter</artifactId>
- <version>3.15.6</version>
- </dependency>
- <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <scope>provided</scope>
- </dependency>
复制代码 大概图解
如上图,先设置application.yml设置Redis的各项属性包罗ip,端口,暗码。再注入。
- server:
- port: 8080
- # Redis配置
- spring:
- redis:
- host: 192.168.200.131
- port: 6379
- password: root
复制代码- // RedisConfigProperties.java
- @Data
- @ConfigurationProperties(prefix = "spring.redis")
- public class RedisConfigProperties {
- private String host;
- private int port;
- private String password;
- }
- // RedisTemplateConfig.java
- @Configuration
- public class RedisTemplateConfig {
- @Autowired
- RedisConfigProperties redisConfigProperties;
- @Bean
- public RedisConnectionFactory redisConnectionFactory() {
- RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(
- redisConfigProperties.getHost(), redisConfigProperties.getPort()
- );
- config.setPassword(redisConfigProperties.getPassword());
- return new LettuceConnectionFactory(config);
- }
- @Bean
- public RedisTemplate<String, Object> redisTemplate(){
- RedisTemplate<String,Object> template = new RedisTemplate<>();
- template.setConnectionFactory(redisConnectionFactory());
- // 设置序列化器等其他配置
- return template;
- }
- }
- // RedissonConfig.java
- @Configuration
- @EnableConfigurationProperties({RedisConfigProperties.class})
- public class RedissonConfig {
- @Autowired
- RedisConfigProperties redisConfigProperties;
- @Bean
- public RedissonClient redissonClient(){
- // 1. 创建配置文件
- Config config = new Config();
- // 2. 设置单节点服务器配置
- config.useSingleServer().setAddress(
- "redis://"+redisConfigProperties.getHost()+":"+redisConfigProperties.getPort()
- );
- // 3. 如果Redis设置了密码,这里需要设置密码
- config.useSingleServer().setPassword(redisConfigProperties.getPassword());
- // 4. 创建RedissonClient实例
- RedissonClient redisson = Redisson.create(config);
- return redisson;
- }
- }
复制代码 到这里,RedisTemplate和Redisson就已经集成好了,后续使用只必要注入就行。
例如
- @RestController
- @RequestMapping(value = "/order")
- public class OrderController {
- @Autowired
- //private RedisTemplate redisTemplate;
- private StringRedisTemplate redisTemplate; //通常用这个StringRedisTemplate
- @Autowired
- private RedissonClient redissonClient;
- ...
- ...
- }
复制代码 3. 模拟分布式场景下超卖现象
OrderController
- /***
- * 抢单
- */
- @GetMapping(value = "/v1/{id}/{num}")
- public String addv1(@PathVariable(value = "id")String id,@PathVariable("num")Long num) throws InterruptedException {
- // 1.查询库存
- int count = Integer.valueOf(redisTemplate.opsForValue().get(id));
- System.out.println("剩余库存:"+count);
- // 2.库存充足
- if (count>=num){
- //模拟操作
- TimeUnit.SECONDS.sleep(5);
- //递减库存
- Long decrement = redisTemplate.opsForValue().decrement(id, num);
- System.out.println("递减库存后剩余库存:"+decrement);
- //其它操作 略
- System.out.println("----添加订单了!");
- return "下单成功";
- }
- //库存不足
- else {
- return "库存不足";
- }
- }
复制代码 复制一个端口为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分布式锁,防止超卖
关键代码
- RLock lock = redissonClient.getLock("mylock_" + id);
- lock.lock(); //自旋获取锁
- ...
- ...
- lock.unlock();
复制代码 首先记得set water 2
OrderController
- /***
- * 抢单,使用分布式锁
- */
- @GetMapping(value = "/{id}/{num}")
- public String add(@PathVariable(value = "id")String id,@PathVariable("num")Long num) throws InterruptedException {
- //对该商品加锁,加锁成功,则判断库存,避免多人同时判断某一个商品的库存
- RLock lock = redissonClient.getLock("mylock_" + id);
- lock.lock(); //自旋获取锁
- System.out.println("获取了锁!"+lock.getName());
- try {
- // 1.查询库存
- int count = Integer.valueOf(redisTemplate.opsForValue().get(id));
- System.out.println("剩余库存:"+count);
- // 2.库存充足
- if (count>=num){
- //模拟操作
- TimeUnit.SECONDS.sleep(5);
- //递减库存
- Long decrement = redisTemplate.opsForValue().decrement(id, num);
- System.out.println("递减库存后剩余库存:"+decrement);
- //其它操作 略
- System.out.println("----添加订单了!");
- return "下单成功";
- }
- //库存不足
- else {
- return "库存不足";
- }
- } finally {
- //释放锁
- System.out.println("释放了锁!"+lock.getName());
- lock.unlock();
- }
- }
复制代码 启动2个服务,欣赏器同时发送2个哀求
http://127.0.0.1:8080/order/water/2
http://127.0.0.1:8081/order/water/2
防止了超卖现象
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |