引言
并发引起的服务器崩溃是非常常见的现象,为了解决这一问题,目前流行使用缓存数据库与消息队列搭配使用。在最近的项目中也是使用到这一手段,本篇文章通过一个案例为大家展示该套方案如何使用。
案例描述与流程
本案例是一个经典的并发下单的案例。在Redis中存在一条key为Apple,Value为10000的数据,为防止超卖问题的发生使用Redisson分布式锁避免超卖(在Redis解决超卖Demo这篇文章中已经讲过),在一个线程拿到锁并且符合下单条件则直接返回下单成功同时发送消息,使用AMQP监听队列消息,通过线程池创建多个线程作为消费者进行底层DB的更新。
环境准备
创建模块名为Redis
yml配置文件的编写
server:
port: 9000
spring:
application:
name: redis
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/user?useSSL=false
username: root
password: 123456
redis:
host: 192.168.136.130
port: 6379
password: 123456
lettuce:
pool:
max-active: 10
max-idle: 10
min-idle: 1
time-between-eviction-runs: 10s
rabbitmq:
host: 192.168.136.130 #MQ地址
port: 5672 #端口
virtual-host: / #虚拟主机
username: demo #用户密码
password: 123321
connection-timeout: 1s
template:
retry: #重试机制
enabled: true
initial-interval: 1000ms
multiplier: 1
max-attempts: 3
publisher-confirm-type: correlated
publisher-returns: true
Controller Test类的编写
设置路径为 /testAddsetxAddFinally
@RestController
@RequestMapping("/")
public class Test {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private RabbitTemplate rabbitTemplate;
/*使用setnx锁,同时给锁释放过期时间,自动释放锁
* */
@RequestMapping("testAddsetxAddFinally")
String cherkAndReduceStockAddSetnxAddFinally()
{
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock-stock", "0000",2, TimeUnit.SECONDS);
//获取锁失败,停止50ms,递归调用
if (!lock){
try {
Thread.sleep(3000);