對創建訂單(秒殺接口)進行壓測(現在只開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;
}
2019-04-21
原因是連接池配置的不夠多,Transaction事務中由于新開了一個生成訂單號的Transaction,如果進來的線程用盡了連接數,新開的訂單號的Transaction得不到有效連接(外部的Transaction會被掛起),導致所有的Transaction都走不下去,最后MySQL超時。
tomcat默認的線程數為1000,所以配置的連接數大于1000就沒有問題了。