秒杀系统应该是很检验一个人的能力的项目。包括从前端
到运营商到nginx到后端等等,很多地方可以优化。
前端的页面控制,运营商的CDN加速,nginx的动静分离等
下面我来一步一步实现后端的秒杀功能的一步一步实现和优化。
后端接口
1,获取商品详情,2,秒杀接口
获取商品:参数 商品ID 通过商品ID返回商品详情。
秒杀接口:参数 商品ID 后端接收商品ID,判断是否有库存,
没有:返回已售完
有:库存-1,创建订单,返回秒杀成功
测试工具 jmeter 测试这2个接口的QPS(每秒处理请求数)
期望结果: 商品能够正常秒杀,不能出现超卖等异常,QPS越高越好。
1.0版本: 不借用其他中间件和优化,正常的操作数据库。实现功能
/**
* 秒杀一般只限购1个,所以数量都是1
* @return 1 成功 0 失败
*/
public int secKill(String seckillId,String userid){
/**
* 第一步:判断当前时间是否在秒杀时间段内
* 第二步:判断是否有库存:有 库存减一 没有直接返回售完
* 第三步:创建订单,返回成功
*/
//判断当前时间是否在秒杀时间段内
JSONObject jsonObject = productService.findById(seckillId);
if(jsonObject==null){
return 0;
}
if(judgeTime(jsonObject.getTimestamp("starttime"),jsonObject.getTimestamp("endtime"))){
return 0;
}
//更新库存减一,成功返回1,失败返回0
int isSelfOut = productDao.updataNumById(seckillId);
if(isSelfOut==0) {
return 0;
}
//创建订单
orderDao.createOrder(seckillId,userid);
return 1;
}
/**
* 如果当前时间在秒杀时间端,返回false,不在返回true
* @param starttime
* @param endtime
* @return
*/
private boolean judgeTime(Timestamp starttime, Timestamp endtime) {
Date date = new Date();
return !(date.getTime()>starttime.getTime()&&date.getTime()<endtime.getTime());
}
判断是否有库存,有 减一 SQL<!-- 这里做判断是否有库存和数量减一操作,
如果库存大于1,则 更新记录返回 1
如果库存等于,更新失败,返回 0
所以是不会出现超卖的现象-->
<update id="updataNumById">
update seckill set inventory=inventory-1
where seckillId=#{seckillId} and inventory>0
</update>
秒杀商品表 :ID,商品名,库存数,开始时间,结束时间:
测试计划:jmeter并发1000。获取商品传入商品ID,秒杀接口传入商品ID和随机11位用户ID
测试结果: 如下图,商品接口 qps 110 秒杀 qps 68,这个跟电脑配置有关。
订单表500表记录,商品表1000的库存变为0,没有出现超卖现象,逻辑正常,数据一致性
第一个版本是正常的没有借用其他组件的,下个博客在此基础上一步步优化。