1. 前言
目的:该项目只用于技术交流,不用于过多商业用途。
适用:可用于简历亮点、毕业答辩等。
2. 项目成果
2.1 秒杀主页
包含5个功能点:
①、Product Name:秒杀商品名称
②、Product Image:秒杀商品图片
③、Price:秒杀价格
④、Seckill starts in:距离秒杀所剩时间
⑤、Seckill Now:秒杀按钮(核心逻辑)
部分不重要参数,没有做UI设计,只为功能而生。
2.2 秒杀架构
①、MySQL主从复制:一主二从
②、Redis缓存、Redis分布式锁
③、MQ异步处理库存、订单
3. 核心代码讲解
3.1 缓存预热
@Override
public void afterPropertiesSet() throws Exception {
// 缓存秒杀商品
List<SeckillGoods> seckillGoodsList = seckillMapper.queryAllSeckillGoods();
for(SeckillGoods goods : seckillGoodsList) {
String goodsId = goods.getId();
Integer stock = goods.getGoodsStock();
HashOperations hashOperations = redisTemplate.opsForHash();
hashOperations.put(CONSTANT.SECKILLGOODS, goodsId, stock);
}
// 缓存秒杀订单
List<SeckillOrder> seckillOrderList = seckillMapper.queryAllSeckillOrder();
for(SeckillOrder seckillOrder : seckillOrderList) {
String userId = seckillOrder.getUserId();
String goodsId = seckillOrder.getGoodsId();
HashOperations hashOperations = redisTemplate.opsForHash();
hashOperations.put(CONSTANT.SECKILLORDER, userId + "," + goodsId, CONSTANT.SECKILLORDER);
}
}
3.2 核心业务逻辑
@Override
public Map<String, String> buySeckillGoods(String userId, String goodsId) {
Map result = new HashMap<String, String>();
RLock lock = redisson.getLock(CONSTANT.SECKILLLOCK); // 拿不到会自己阻塞
try {
lock.lock();
// 检查Redis秒杀商品是否有库存
Integer stock = (Integer) redisTemplate.opsForHash().get(CONSTANT.SECKILLGOODS, goodsId);
if(stock <= 0) {
result.put("msg", "秒杀商品库存不足!");
result.put("success", "400");
return result;
}
// 检查该用户是否秒杀过该商品
Object orderConstant = redisTemplate.opsForHash().get(CONSTANT.SECKILLORDER, userId + "," + goodsId);
if(orderConstant != null) {
result.put("msg", "该用户已经秒杀过该商品了!");
result.put("success", "400");
return result;
}
// Redis新增订单
String orderId = UUID.randomUUID().toString();
SeckillOrder seckillOrder = new SeckillOrder();
seckillOrder.setId(orderId);
seckillOrder.setGoodsId(goodsId);
seckillOrder.setUserId(userId);
redisTemplate.opsForHash().put(CONSTANT.SECKILLORDER, userId + "," + goodsId, CONSTANT.SECKILLORDER);
// Redis减少库存
redisTemplate.opsForHash().put(CONSTANT.SECKILLGOODS, goodsId, stock-1);
// MQ处理库存和订单
rabbitTemplate.convertAndSend("seckillGoodsExchange", "seckillGoodsRouting", seckillOrder);
rabbitTemplate.convertAndSend("seckillOrderExchange", "seckillOrderRouting", seckillOrder);
}catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock(); // 解锁
}
result.put("msg", "秒杀商品成功!");
result.put("success", "200");
return result;
}
4. 其他
还存在其他的补充点(订单支付超时、订单真实支付、MQ消息问题、Redis单机问题等),如果喜欢请三连,我会继续更新。
需要完整代码或帮忙搭建环境,请留下邮箱。