对创建订单(秒杀接口)进行压测(现在只开10个线程循环1次),会报如下错误
The error occurred while setting parameters### SQL: update item_stock set stock = stock - ? where stock >= ? and item_id = ?### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction; Lock wait timeout exceeded; try restarting transaction; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction]2019-04-16 16:45:17.323 WARN 11904 --- [nio-8080-exec-7] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.dao.CannotAcquireLockException:
已经对相应字段添加过索引了,不能解决问题。即使仅保留 减库存 生成订单号 订单入库 三个操作仍旧是会出现上边的问题。
public OrderModel createOrder(Integer userId, Integer itemId, Integer promoId, Integer amount) throws BusinessException {
// 校验状态:用户是否存在,商品是否存在,数量是否合法,活动是否合法
// 在getItemById方法中创建itemModel时就已经判断了服务器时间活动状态
ItemModel itemModel = itemService.getItemById(itemId);
if(itemModel == null)
throw new BusinessException(EmBusinessError.ITEM_NOT_EXIST);
UserModel userModel = userService.getUserById(userId);
if(userModel == null)
throw new BusinessException(EmBusinessError.USER_NOT_EXIST);
if(amount <=0 || amount >99)
throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,"购买数量过大");
if(promoId != null){
// 非空,比较是否同一个活动
if(!promoId.equals(itemModel.getPromoModel().getId()))
throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,"不存在该活动");
// 活动是否在进行中
else if(itemModel.getPromoModel().getStatus() != 2)
throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,"活动不在进行中");
}
// 减库存的两种方式:下单减库存和支付减库存
// 下单减库存是指,当提交订单时查询是否有剩余可买的商品,如果有就将商品“加锁”(数量减一),并完成下单,再去支付
// 支付减库存是指,当提交订单时仅仅查询是否有剩余可买的商品,不对其加锁,直到支付完成才减库存。
// 下单减库存能确保下单后一定能获得商品。支付减库存在并发下存在超卖商品风险
// 某些商家库存120件,表明的是100件,采用下单减库存可以承受20件的超卖风险,同时能营造出 火爆和售罄的紧张感
// 采用下单减库存方式
boolean isDecreased = itemService.decreaseStock(itemId,amount);
if(!isDecreased)
throw new BusinessException(EmBusinessError.STOCK_NOT_ENOUGH);
// 订单入库
OrderModel orderModel = new OrderModel();
orderModel.setUserId(userId);
orderModel.setItemId(itemId);
orderModel.setAmount(amount);
orderModel.setPromoId(promoId);
if(promoId == null)
orderModel.setItemPrice(itemModel.getPrice());
else orderModel.setItemPrice(itemModel.getPromoModel().getPromoItemPrice());
orderModel.setOrderPrice(orderModel.getItemPrice().multiply(BigDecimal.valueOf(amount)));
// 生成交易流水号
orderModel.setId(sequenceService.generateOrderId());
OrderDataObject orderDataObject = convertOrderDataFromOrderModel(orderModel);
orderDataObjectMapper.insertSelective(orderDataObject);
// 销量增加,暂时不考虑支付金额的情况
itemService.increaseSales(itemId,amount);
// 返回Controller
return orderModel;
}