# 秒杀系统
**Repository Path**: carpedil/second-kill-system
## Basic Information
- **Project Name**: 秒杀系统
- **Description**: No description available
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2021-02-07
- **Last Updated**: 2024-12-22
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 秒杀系统
## 应用场景
- 电商抢购限量商品
- 明星演唱会门票
- 火车票12306
- ....
# 为什么要做个系统
```Java
如果项目的流量非常小,完全不担心有并发的购买请求,那么做这个秒杀系统意义不大,但是如果项目的系统要像12306那样,接收高并发和下单的考验,那么就需要一套完整的流程保护措施
那么一个秒杀系统完整的保护流程应该有以下几个方面:
1.严格防止超卖:
库存100,但是卖了1000件,等着跟用户扯皮吧
2.防止黑产:
防止不怀好意的人群通过技术手段,把本来应该发给客户群体的利益收入囊中
3.保证用户体验:
高并发下,别网页打不开了,支付不了,购物车进不去,地址改不了等等
```
# 保护措施
- 乐观锁防止超卖 (悲观锁`同步代码块`也可以解决超卖,但是不推荐)
- 令牌桶限流
- redis 缓存
- 消息队列异步处理订单
> 悲观锁防止超卖代码实现
```java
// 控制层
@GetMapping("kill")
public String stockKill(Integer id){
System.out.println("商品id = "+id);
try{
// 使用悲观锁防止超卖,但是不推荐这种方式,效率很低
synchronized (this){
// 调用秒杀业务
return"秒杀成功:"+String.valueOf(orderService.kill(id));
}
}catch(Exception e){
e.printStackTrace();
return e.getMessage();
}
}
// 业务层
@Override
@Transactional(rollbackFor = Exception.class)
public int kill(Integer id){
// 根据商品id校验库存
Stock stock=stockMapper.checkStockById(id);
if(stock.getCount().equals(stock.getSale())){
throw new RuntimeException("库存不足");
}else{
// 减扣库存
stock.setSale(stock.getSale()+1);
stockMapper.updateStock(stock);
// 创建订单
Order order=
new Order()
.setSid(stock.getId())
.setName(stock.getName())
.setCreateTime(LocalDateTime.now());
orderMapper.createOrder(order);
return order.getId();
}
}
```
```xml
update stock
set sale = #{sale}
where id = #{id}
and version = #{version}
```
> 乐观锁防止超卖代码实现
> 先将业务层代码进行拆分,分步实现,主要区别在减扣库存,悲观锁是从Java代码层面实现库存减扣
> 乐观锁是在sql语句层面实现减扣库存,同时加入了版本号,利用的是数据库在操作的时候,会对被操作的资源进行加锁的特性实现的(事务)
```java
// 校验库存
private Stock checkStock(Integer id){
// 根据商品id校验库存
Stock stock=stockMapper.checkStockById(id);
if(stock.getCount().equals(stock.getSale())){
throw new RuntimeException("库存不足");
}
return stock;
}
// 减扣库存
private void updateSale(Stock stock){
// 减扣库存
int updateRowCount=stockMapper.updateStock(stock);
if(updateRowCount==0){
throw new RuntimeException("抢购失败");
}
}
// 创建订单
```
> 令牌桶限流
```xml
com.google.guava
guava
28.2-jre
```
```java
/** 创建令牌桶实例 设置初始令牌数:10个 */
private RateLimiter rateLimiter=RateLimiter.create(20);
@GetMapping("killToken")
public String stockKillToken(Integer id){
System.out.println("商品id = "+id);
if(rateLimiter.tryAcquire(3,TimeUnit.SECONDS)){
log.info("活动过于火爆,服务器爆满,请求被抛弃,请重试!!!");
return"抢购失败,活动过于火爆,服务器爆满,请重试!!!";
}
try{
// 调用秒杀业务
return"秒杀成功:"+String.valueOf(orderService.kill(id));
}catch(Exception e){
e.printStackTrace();
return e.getMessage();
}
}
```