Configure Redis

Redis: host: 192.168.203.124 Port: 6379 # Redis database index Database: 0 timeout: 10000ms lettuce: Pool: max-active: 8 max-wait: 10000ms max-idle: 200 min-idle: 5Copy the code

First, you need to define your own RedisTemplate

So here we’re configuring <key,value> of type <String,Object>

@Configuration public class RedisConfig { @Bean(value = "myRedisTemplate") public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){ RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); / / key serialization redisTemplate. SetKeySerializer (new StringRedisSerializer ()); / / value serialization redisTemplate. SetValueSerializer (new GenericJackson2JsonRedisSerializer ()); redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setConnectionFactory(redisConnectionFactory); return redisTemplate; }}Copy the code

The use of the RabbitMQ

Here we have chosen to use Topic mode, first we will write our own configuration class for RabbitMQ

@Configuration public class RabbitMQTopicConfig { private static final String QUEUE = "seckillQueue"; private static final String EXCHANGE = "seckillExchange"; @bean public Queue Queue(){return new Queue(Queue); } /** * switch * @return */ @bean public TopicExchange TopicExchange(){return new TopicExchange(EXCHANGE); } /** *topic mode * @return */ @bean public Binding Binding (){return BindingBuilder.bind(queue()).to(topicExchange()).with("seckill.#"); }}Copy the code

RabbitMQ uses the producer-consumer model, which corresponds to senders and receivers, and we need to set up our own senders and receivers. The sender is:

public class MQSender { @Autowired private RabbitTemplate rabbitTemplate; Public void sendKillMessage(String message){log.info(" send message :" + message); rabbitTemplate.convertAndSend("seckillExchange","seckill.message",message); }}Copy the code

The sender simply sends the message through the message queue, and the receiver can perform the corresponding business operation after receiving the message, which realizes the asynchronous operation.

public class MQReciver { @Autowired private IGoodsService iGoodsService; @Autowired @Qualifier("myRedisTemplate") private RedisTemplate redisTemplate; @Autowired private OrderServiceImpl orderService; /** * queues */ @rabbitListener (queues = "seckillQueue") public void recive(String message){seckillMessage seckillMessage1 = new seckillMessage(); Log.info (" Received message: "+ message); String s = JacksonUtil.toJson(message); seckillMessage seckillMessage = JacksonUtil.fromJson(message, seckillMessage1.getClass()); Long goodsId = seckillMessage.getGoodsId(); User user = seckillMessage.getUser(); GoodsVo goodsVo = iGoodsService.listGoods(goodsId); if(goodsVo.getStockCount() < 1){ return; } SeckillOrder seckillOrder = (SeckillOrder) redisTemplate.opsForValue().get("order:" + user.getId() + ":" + goodsId); if(seckillOrder ! = null){ return ; } orderService.sekill(user, goodsVo); }}Copy the code

The specific application of placing orders in the second kill system

An important sign of success is to generate the order in the database, so we need to ensure that the order data is correct.

  • [1] When our system is initialized, we should load the inventory quantity into Redis in advance
@override public void afterPropertiesSet() throws Exception {redis * @override public void afterPropertiesSet() throws Exception { List<GoodsVo> goods = iGoodsService.getGoods(); if(CollectionUtils.isEmpty(goods)){ return; } goods.forEach(goodsVo -> { redisTemplate.opsForValue().set("seckillGoods" + goodsVo.getId(), goodsVo.getGoodsStock());  EmptyStockMap.put(goodsVo.getId(),false); }); }Copy the code
  • [2] At the beginning of the second kill, a large number of users are about to access the data we have loaded into Redis in advance. In order to relieve the pressure of Redis, we can adopt the method of memory marking to reduce the pressure of Redis.
Private Map<Long,Boolean> EmptyStockMap = new HashMap<>();Copy the code
  • [3] After the user visits Redis, we do not immediately generate corresponding orders to the database, but should pre-reduce the inventory of Redis
Long stock = valueOperations.decrement("seckillGoods" + goodsId); Emptystockmap.put (goodsId,true); emptyStockmap.put (goodsId,true); valueOperations.increment("seckillGoods"+goodsId); return "not enough"; }Copy the code
  • [4] At the end of the process, we can finally call RabbitMQ to perform an asynchronous operation on the database
seckillMessage seckillMessage = new seckillMessage(user, goodsId);
mqSender.sendKillMessage(JacksonUtil.toJson(seckillMessage));
Copy the code