對(duì)創(chuàng)建訂單(秒殺接口)進(jìn)行壓測(cè)(現(xiàn)在只開10個(gè)線程循環(huán)1次),會(huì)報(bào)如下錯(cuò)誤
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:
已經(jīng)對(duì)相應(yīng)字段添加過索引了,不能解決問題。即使僅保留?減庫(kù)存??生成訂單號(hào)??訂單入庫(kù)??三個(gè)操作仍舊是會(huì)出現(xiàn)上邊的問題。
public?OrderModel?createOrder(Integer?userId,?Integer?itemId,?Integer?promoId,?Integer?amount)?throws?BusinessException?{
????//?校驗(yàn)狀態(tài):用戶是否存在,商品是否存在,數(shù)量是否合法,活動(dòng)是否合法
????//?在getItemById方法中創(chuàng)建itemModel時(shí)就已經(jīng)判斷了服務(wù)器時(shí)間活動(dòng)狀態(tài)
????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,"購(gòu)買數(shù)量過大");
????if(promoId?!=?null){
????????//?非空,比較是否同一個(gè)活動(dòng)
????????if(!promoId.equals(itemModel.getPromoModel().getId()))
????????????throw?new?BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,"不存在該活動(dòng)");
????????//?活動(dòng)是否在進(jìn)行中
????????else?if(itemModel.getPromoModel().getStatus()?!=?2)
????????????throw?new?BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,"活動(dòng)不在進(jìn)行中");
????}
????//?減庫(kù)存的兩種方式:下單減庫(kù)存和支付減庫(kù)存
????//?下單減庫(kù)存是指,當(dāng)提交訂單時(shí)查詢是否有剩余可買的商品,如果有就將商品“加鎖”(數(shù)量減一),并完成下單,再去支付
????//?支付減庫(kù)存是指,當(dāng)提交訂單時(shí)僅僅查詢是否有剩余可買的商品,不對(duì)其加鎖,直到支付完成才減庫(kù)存。
????//?下單減庫(kù)存能確保下單后一定能獲得商品。支付減庫(kù)存在并發(fā)下存在超賣商品風(fēng)險(xiǎn)
????//?某些商家?guī)齑?20件,表明的是100件,采用下單減庫(kù)存可以承受20件的超賣風(fēng)險(xiǎn),同時(shí)能營(yíng)造出?火爆和售罄的緊張感
????//?采用下單減庫(kù)存方式
????boolean?isDecreased?=?itemService.decreaseStock(itemId,amount);
????if(!isDecreased)
????????throw?new?BusinessException(EmBusinessError.STOCK_NOT_ENOUGH);
????//?訂單入庫(kù)
????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)));
????//?生成交易流水號(hào)
????orderModel.setId(sequenceService.generateOrderId());
????OrderDataObject?orderDataObject?=?convertOrderDataFromOrderModel(orderModel);
????orderDataObjectMapper.insertSelective(orderDataObject);
????//?銷量增加,暫時(shí)不考慮支付金額的情況
????itemService.increaseSales(itemId,amount);
????//?返回Controller
????return?orderModel;
}
2019-04-21
原因是連接池配置的不夠多,Transaction事務(wù)中由于新開了一個(gè)生成訂單號(hào)的Transaction,如果進(jìn)來的線程用盡了連接數(shù),新開的訂單號(hào)的Transaction得不到有效連接(外部的Transaction會(huì)被掛起),導(dǎo)致所有的Transaction都走不下去,最后MySQL超時(shí)。
tomcat默認(rèn)的線程數(shù)為1000,所以配置的連接數(shù)大于1000就沒有問題了。