解决Redis超卖问题
生活随笔
收集整理的这篇文章主要介绍了
解决Redis超卖问题
小编觉得挺不错的,现在分享给大家,帮大家做个参考.
第一种:使用synchronized(只适用于单个tomcat)
@Autowired private StringRedisTemplate stringRedisTemplate; @GetMapping("/deduct")public String toDeduct(){synchronized (this) {int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));if (stock > 0) {Long stock1 = stringRedisTemplate.opsForValue().decrement("stock");System.out.println("扣减成功,剩余库存:" + stock1);}else{System.out.println("扣减失败,库存不足");}return "end";}}第二种:使用SETNX命令(多台tomcat)
@GetMapping("/deduct_stock")public String deductStock() throws InterruptedException {String lockKey = "lockKey";//设计唯一key值防止锁失效问题String clientId = UUID.randomUUID().toString();//设计锁超时时间,防止服务器宕机时锁没有释放掉(finally语句没有执行)Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, clientId, 10, TimeUnit.SECONDS);//jedis.setnx(key,value);//若键 key 已经存在, 则 SETNX 命令不做任何动作。result==falseif (!result) {return "正在排队。。。";}try {int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));if (stock > 0) {Long realStock = stringRedisTemplate.opsForValue().decrement("stock");System.out.println("扣减成功,剩余库存:" + realStock);}else{System.out.println("扣减失败,库存不足");}} finally {//防止锁失效问题,在多线程的情况下,每个线程只释放自己创建的锁,线程之间互不干预。if(clientId.equals(stringRedisTemplate.opsForValue().get(lockKey))) {stringRedisTemplate.delete(lockKey);}}return "end";}第三种:使用Redission框架(原理跟第二种一样)
1、配置config类
@Configuration public class RedissonConfig {@Value("${spring.redis.host}")private String host;@Value("${spring.redis.port}")private String port;@Value("${spring.redis.password}")private String password;@Beanpublic RedissonClient getRedisson(){Config config = new Config();config.useSingleServer().setAddress("redis://" + host + ":" + port).setPassword(password);//添加主从配置 // config.useMasterSlaveServers().setMasterAddress("").setPassword("").addSlaveAddress(new String[]{"",""});return Redisson.create(config);} } @GetMapping("/deduct_stock1")public String deductStock1(){String lockKey = "lockKey";RLock redissonLock = redisson.getLock(lockKey);try {redissonLock.lock();int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));if (stock > 0) {Long realStock = stringRedisTemplate.opsForValue().decrement("stock");System.out.println("扣减成功,剩余库存:" + realStock);}else{System.out.println("扣减失败,库存不足");}} finally {redissonLock.unlock();}return "end";}Redission原理:
Redission使用了Lua 脚本,实现原理跟原理跟第二种差不多。
当业务代码处理时间很长,像mysql慢查询等等,可以在try代码块中每隔10秒检查是否还持有锁,如果持有则延长锁的时间,防止还没执行完业务代码“lockKey”就到了失效时间。
测试环境搭建
Redis命令大全
设置Redis密码
pom:
application.properties:
server.port=8090 # redis spring.redis.host=127.0.0.1 spring.redis.port=6379 spring.redis.password=888888 spring.redis.jedis.pool.max-active=500 spring.redis.jedis.pool.max-idle=1000 spring.redis.jedis.pool.max-wait=6000ms spring.redis.jedis.pool.min-idle=4Nginx负载均衡:
upstream redislock{server 127.0.0.1:8080 weight = 1;server 127.0.0.1:8090 weight = 1;}server {listen 80;server_name localhost;location / {root html;index index.html index.htm;proxy_pass http://redislock;}}Jmeter压力测试
发送http请求:
设置发送地址:
表示在0秒内发送200个请求,处理完后再发送200 * 3次,总计200 * 4次请求:
结果集:
测试结果:
没有出现超卖问题
总结
以上是生活随笔为你收集整理的解决Redis超卖问题的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: Review学生作业管理系统
- 下一篇: python3安装mysql模块_Pyt