兰州网站seo费用,erp软件实施,393网站,扬州市住房和城乡建设局网站一#xff0c;代码如下Transactional(rollbackFor Exception.class)
public void updateDelivery(){
// 1.新增反馈记录
// 2.更新订单状态#xff0c;及其他字段
// 3.新增变更履历
// 4.其他新增逻辑及与其他系统交互逻辑
}二#xff0c;问题偶尔出现#xff08;概率极低…一代码如下 Transactional(rollbackFor Exception.class)
public void updateDelivery(){
// 1.新增反馈记录
// 2.更新订单状态及其他字段
// 3.新增变更履历
// 4.其他新增逻辑及与其他系统交互逻辑
}二问题偶尔出现概率极低步骤2中订单更新失败状态没有更新最初听说只是状态这个字段没有更新成功其实还有其他字段是都没有更新即没有进行更新操作。具体更新逻辑是当前状态是10想更新成20结果还是10。三猜想与分析猜想1执行代码时出现了异常但是经过查看步骤134都执行成功了直到方法最后并没有出现异常猜想2业务逻辑中该状态变更不符合具体场景由于猜想1中13执行成功且经过代码分析不存在这种问题猜想3更新时出现了死锁这条数据在其他地方也在更新且对方持有该数据锁行锁导致这里更新失败具体可能出现同时更新的场景有两个有一个job会查询状态是10的订单数据会写入一个中间表然后更新这条订单数据job更新成功并发导致两个请求同时调用该接口请求1想更新成10请求2想更新成20由于业务逻辑比较长请求1持有该数据锁请求2无法更新成功可能出现了死锁针对场景2具体再分析实际上两次请求应该都会更新成功请求2会等待请求1事物结束然后再去更新数据也不会出现死锁可以模拟下这种并发场景。具体代码如下请求1进来更新后休眠20s保证事物不结束保证持有该数据行锁这个应该是这样请求2进来并没有出现异常且状态也会正常更新。 ApiOperation(value 模拟更新订单主表异常-并发1, notes 模拟更新订单主表异常-并发1)PostMapping(value updateDeliveryException1)Transactional(rollbackFor Exception.class)public PpDelivery updateDeliveryException1(RequestBody PpDelivery ppDelivery) {tiExceptionLogService.insertExceptionRecord(ppDelivery, , 模拟事物问题);for (int i 0; i 3; i) {Integer result 0;Boolean isException false;try {result ppDeliveryService.updatePpDelivery(ppDelivery);Thread.sleep(20000);if (result 1) {break;}} catch (Exception e) {logger.error(ylToDPSOrderStatusFeedbackImpl update exception ppDelivery: {}, JSON.toJSONString(ppDelivery, SerializerFeature.WriteMapNullValue), e);tiExceptionLogService.insertExceptionRecord(ppDelivery, e.getMessage(), 更新订单主表失败数据库执行新增异常);isException true;}if (result 0 Boolean.FALSE.equals(isException)) {logger.error(ylToDPSOrderStatusFeedbackImp update failed ppDelivery: {}, JSON.toJSONString(ppDelivery, SerializerFeature.WriteMapNullValue));tiExceptionLogService.insertExceptionRecord(ppDelivery, String.valueOf(result), 更新订单主表失败数据库执行新增未返回成功);}try {Thread.sleep(1000);} catch (InterruptedException e) {logger.error(ylToDPSOrderStatusFeedbackImpl interruptedException ppDelivery: {}, JSON.toJSONString(ppDelivery, SerializerFeature.WriteMapNullValue));}}return ppDelivery;} ApiOperation(value 模拟更新订单主表异常-并发2, notes 模拟更新订单主表异常-并发2)PostMapping(value updateDeliveryException2)Transactional(rollbackFor Exception.class)public PpDelivery updateDeliveryException2(RequestBody PpDelivery ppDelivery) {tiExceptionLogService.insertExceptionRecord(ppDelivery, , 模拟事物问题);for (int i 0; i 3; i) {Integer result 0;Boolean isException false;try {result ppDeliveryService.updatePpDelivery(ppDelivery);if (result 1) {break;}} catch (Exception e) {logger.error(ylToDPSOrderStatusFeedbackImpl update exception ppDelivery: {}, JSON.toJSONString(ppDelivery, SerializerFeature.WriteMapNullValue), e);tiExceptionLogService.insertExceptionRecord(ppDelivery, e.getMessage(), 更新订单主表失败数据库执行新增异常);isException true;}if (result 0 Boolean.FALSE.equals(isException)) {logger.error(ylToDPSOrderStatusFeedbackImp update failed ppDelivery: {}, JSON.toJSONString(ppDelivery, SerializerFeature.WriteMapNullValue));tiExceptionLogService.insertExceptionRecord(ppDelivery, String.valueOf(result), 更新订单主表失败数据库执行新增未返回成功);}try {Thread.sleep(1000);} catch (InterruptedException e) {logger.error(ylToDPSOrderStatusFeedbackImpl interruptedException ppDelivery: {}, JSON.toJSONString(ppDelivery, SerializerFeature.WriteMapNullValue));}}return ppDelivery;}
通过以上分析如果排除场景2很可能就是场景1了。且查询更新时间job中这条数据更新与最初代码中步骤3的时间完全问好四解决方案调整job执行频率由1min改成5分钟避免同时取到订单数据进行更新job逻辑中改循环查询更新为直接更新减少整个方法执行时间缩短大事物五疑问查看数据库死锁日志并没有发现出现死锁记录show engin innodb status如果这个信息准确又是什么原因没有更新成功呢job中并没有声明式事物会存在大事物问题吗代码如下/** 订单状态存中间表定时器*
*/
JobHandler(value orderStatusToTiHandler)
Component
public class OrderStatusToTiHandler extends IJobHandler {Autowiredprivate OrderStatusDispatchToAllService orderStatusDispatchToAllService;Autowiredprivate IPpDeliveryService ppDeliveryService;Autowiredprivate IBasCarrierService basCarrierService;Autowiredprivate ISysSettingService sysSettingService;private static final Logger logger LoggerFactory.getLogger(OrderStatusToTiHandler.class);Overridepublic ReturnTString execute(String s){logger.info(订单状态存中间表定时任务开始运行运行);ListString statusNotIn Arrays.asList(66,90, 99);ListString statusIn Arrays.asList(6020, 6025, 6050, 6055, 100,6045);PpDelivery ppDeliveryQurey new PpDelivery();ppDeliveryQurey.setInterfaceStatus(0);ppDeliveryQurey.setSortName(delivery_no);ppDeliveryQurey.setSortOrder(ASC);ListPpDelivery ppDeliveries ppDeliveryService.queryAllByValuesAndStatus(ppDeliveryQurey, statusIn.toArray(new String[statusIn.size()]), statusNotIn.toArray(new String[statusNotIn.size()]));if (ppDeliveries.size() 0) {logger.info(订单状态存中间表定时任务运行成功);return SUCCESS;}for (PpDelivery ppDelivery : ppDeliveries) {if(StringUtils.isNotBlank(ppDelivery.getTmBasCarrierId())){String receiver this.judgeCarrierPlatform(ppDelivery.getTmBasCarrierId());if(StringUtils.isNotBlank(receiver)){orderStatusDispatchToAllService.orderStatusFeedBackToTi(ppDelivery.getTtPpDeliveryId(), receiver_ ppDelivery.getCurrentStatus());}}}logger.info(订单状态存中间表定时任务运行成功);return SUCCESS;}3改声明式事物为编程式事物有用吗如果把最初的代码中步骤2更新逻辑抽离出来使用编程式事物同时把整个方法声明式事物去掉这种改造目的是缩短大事物但是好像又是针对并发场景下大事物问题但是上面已经验证并发场景下会顺序执行等待前面事物结束以上分析可能存在不足欢迎大佬指正不胜感激