记录偶发更新失败问题
一,代码如下
@Transactional(rollbackFor = Exception.class)
public void updateDelivery(){
// 1.新增反馈记录
// 2.更新订单状态,及其他字段
// 3.新增变更履历
// 4.其他新增逻辑及与其他系统交互逻辑
}
二,问题
偶尔出现(概率极低)步骤2中订单更新失败,状态没有更新,最初听说只是状态这个字段没有更新成功,其实还有其他字段,是都没有更新,即没有进行更新操作。具体更新逻辑是当前状态是10,想更新成20,结果还是10。
三,猜想与分析
猜想1,执行代码时出现了异常,但是经过查看步骤1,3,4都执行成功了,直到方法最后,并没有出现异常
猜想2,业务逻辑中该状态变更不符合具体场景,由于猜想1中1,3执行成功,且经过代码分析,不存在这种问题
猜想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 ReturnT<String> execute(String s){logger.info("订单状态存中间表定时任务开始运行运行");List<String> statusNotIn = Arrays.asList("66","90", "99");List<String> statusIn = Arrays.asList("6020", "6025", "6050", "6055", "100","6045");PpDelivery ppDeliveryQurey = new PpDelivery();ppDeliveryQurey.setInterfaceStatus("0");ppDeliveryQurey.setSortName("delivery_no");ppDeliveryQurey.setSortOrder("ASC");List<PpDelivery> 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更新逻辑抽离出来,使用编程式事物,同时把整个方法声明式事物去掉,这种改造目的是缩短大事物,但是好像又是针对并发场景下大事物问题,但是上面已经验证并发场景下,会顺序执行,等待前面事物结束
以上分析可能存在不足,欢迎大佬指正,不胜感激
相关文章:
记录偶发更新失败问题
一,代码如下Transactional(rollbackFor Exception.class) public void updateDelivery(){ // 1.新增反馈记录 // 2.更新订单状态,及其他字段 // 3.新增变更履历 // 4.其他新增逻辑及与其他系统交互逻辑 }二,问题偶尔出现(概率极低…...
AI环境搭建步骤(Windows环境)
1. 安装好Anaconda3版本(1) 安装链接:https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/?CM&OD本文使用Anaconda3下载链接:Anaconda5(2) 注意安装anaconda时一定要把环境变量加入windows环境中。要没有勾选,安装完后还有手动加入…...
Linux系统之history命令的基本使用
Linux系统之history命令的基本使用一、history命令介绍二、本地环境检查1本地系统版本2.检查操作系统的内核版本三、history的命令帮助四、history命令的基本帮助1.查看所有历史执行命令2.指定历史命令条数3.清除历史命令记录4.引用历史命令5.将历史文件中的信息读入到当前缓冲…...
花7000报了培训班,3个月后我成功“骗”进了阿里,月薪拿16K....
“月薪4000元不如报名学IT,挑战年薪百万”这是大多数培训班在互联网上宣传的口号,简单的16个字却戳中了很多人的痛点,同龄人买车买房,自己却拿着微薄的工资连好一点的房子都租不起,这句口号 彻底激起了底层员工的焦虑&…...
Java-枚举类的使用(详解)
枚举类的使用前言一、何为枚举类?二、自定义枚举类(JDK1.5之前)1、实现1.1 属性1.2 构造器2、代码演示三、用关键字enum定义枚举类(JDK 1.5)1、实现1.1 属性1.2 构造器2、代码演示四、Enum类的方法五、实现接口的枚举类…...
Docker----------Docker轻量级可视化工具Portainer/监控之 CAdvisor+InfluxDB+Granfana
1.是什么 Portainer 是一款轻量级的应用,它提供了图形化界面,用于方便地管理Docker环境,包括单机环境和集群环境。 2 官网 官网 https://www.portainer.io/ https://docs.portainer.io/v/ce-2.9/start/install/server/docker/linux 3.…...
景嘉微7201
220112-驱动与固件-景嘉微7201驱动与固件-三期超翔TF830JM7201显卡黑屏、花屏、竖线或待机唤醒黑屏JM72系列为了让驱动和系统内核解绑,驱动包含核内和核外两个驱动,两个驱动请都务必安装;最近JM7201 替代R7 340 发货了,导致对应通…...
串口、终端应用程序 API termios
UART简介 串口全称为串行接口,也称为COM接口,串行接口指的是比特一位位顺序传输,通信线路简单。使用两根线就可以实现双向通信,一条为TX,一个为RX。串口通信距离远,但速度相对慢,是一种常用的工…...
【服务器搭建】教程七:如何为自己的网站添加运行时间?
前言 哈喽,大家好,我是木易巷! 上一篇服务器搭建个人网站教程是给大家介绍了:网站如何添加备案号? 今天分享:如何为自己的网站添加运行时间? 木易巷添加网页运行时间后的效果 其实和昨天的添…...
【消息中间件】Apache Kafka 教程
文章目录Apache Kafka 概述什么是消息系统?点对点消息系统发布 - 订阅消息系统什么是Kafka?好处用例需要KafkaApache Kafka 基础(一)消息系统1、点对点的消息系统2、发布-订阅消息系统(二)Apache Kafka 简介…...
ARM基础
文章目录1.ARM成长史1.1 ARM发展的里程碑11.2 ARM发展的里程碑21.3 ARM发展的里程碑31.4 ARM发展的里程碑42.ARM的商业模式和生态系统3.先搞清楚各种版本号3.1 ARM 的型号命名问题3.2 ARM 的几种版本号3.3 ARM型号的发展历程4.SoC和CPU的区别 & 外设概念的引入4.1 SoC和CPU…...
Python排序 -- 内附蓝桥题:错误票据,奖学金
排序 ~~不定时更新🎃,上次更新:2023/02/28 🗡常用函数(方法) 1. list.sort() --> sort 是 list 的方法,会直接修改 list 举个栗子🌰 li [2,3,1,5,4] li.sort() print(li) …...
容器化部署是什么意思?有什么优势?
多小伙伴不知道容器化部署是什么意思?不知道容器化部署有什么优势?今天我们就来一起看看。 容器化部署是什么意思? 容器化部署是指将软件代码和所需的所有组件(例如库、框架和其他依赖项)打包在一起,让它…...
1.设计模式简介
一、设计模式的目的 1. 代码重用性 2. 可读性 3. 可扩展性 4. 可靠性 5. 高内聚,低耦合 二、设计模式七大原则 1. 单一职责原则 1)降低类的复杂度,一个类只负责一项职责 2)提高类的可读性,可维护性 3&#x…...
【算法题解】实现一个包含“正负数和括号”的基本计算器
这是一道 困难 题。 题目来自:leetcode 题目 给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。 注意: 不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval() 。 提示: s 由数字、‘’、‘-’…...
网站服务器如何防护攻击?网站服务器被挂马如何检测
网站服务器是指安装在互联网上的服务器,主要用于提供网站服务。由于网站服务器的重要性,它也是攻击者的活动焦点,因此如何防护攻击就显得尤为重要。本文将分析网站服务器是如何被攻击的以及如何防护攻击。 网站服务器是怎么被攻击的? 网站…...
JavaSE16-面向对象-接口
文章目录一、概念二、格式1.使用interface来定义接口2.implements实现接口三、接口中的成员1.常用成员2.新增成员(不重要)2.1 默认方法2.2 静态方法2.3 私有方法四、继承关系 & 实现关系五、抽象类和接口的使用区别一、概念 接口就是规范\规则&…...
安卓设备蓝牙键盘快捷键
安卓设备蓝牙键盘快捷键前言注意鼠标按键系统快捷键桌面快捷键输入法快捷键其它快捷键旧快捷键(已失效)前言 安卓设备可以通过蓝牙或有线外接键盘,值得一提的是,安卓平板连接蓝牙键盘和蓝牙鼠标是一个不错的组合。本文以鸿蒙3.0平…...
Puppeteer项目结构梳理
最近接触了一个个人感觉很奈斯的项目,故记录思路如下: puppeteer项目梳理: 入口文件 run.js 入口命令 node run.js YourConfig.json 1、我们可以在自己的config.json里面设置好 ①、登录的用户名密码;aws或其它服务器的access等id,accessKey…...
(02)Unity HDRP Volume 详解
1.概述这篇文章主要针对HDRP中的Volume和Volume Post-processing进行解释,针对于各个组件只能进行部分参数的解释,具体的信息可参考官方资料,这里只是对官方文档的图片效果补充以及笔者自己的理解。看到这里进入正文,请确保你的Un…...
拒绝B站邀约,从月薪3k到年薪47W,我的经验值得每一个测试人借鉴
有时候,大佬们总是会特立独行。因为像我这样的常人总是想不通,究竟是怎样的情境,连B站这样的大厂面试都可以推掉? 缘起一通电话,踏出了改变人生轨迹的第一步 我是小瑾,今年28岁,2016年毕业于陕…...
分享一种实用redis原子锁的方式
1. setnx(lockkey, 当前时间过期超时时间) ,如果返回1,则获取锁成功;如果返回0则没有获取到锁,转向2。2. get(lockkey)获取值oldExpireTime ,并将这个value值与当前的系统时间进行比较,如果小于当前系统时间…...
【华为OD机试】 字符串解密(C++ Java JavaScript Python)
题目描述 给定两个字符串string1和string2。 string1是一个被加扰的字符串。 string1由小写英文字母(’a’’z’)和数字字符(’0’’9’)组成,而加扰字符串由’0’’9’、’a’’f’组成。 string1里面可能包含0个或多个加扰子串,剩下可能有0个或多个有效子串,这些有…...
金三银四,助力你的大厂梦,2023年软件测试经典面试真题(1)(共3篇)
前言 金三银四即将到来,相信很多小伙伴要面临面试,一直想着说分享一些软件测试的面试题,这段时间做了一些收集和整理,下面共有三篇经典面试题,大家可以试着做一下,答案附在后面,希望能帮助到大…...
假如面试官要你手写一个promise
promise 在开发中,经常需要用到promise,promise具有很多特性,这一次将对promise特性进行总结,并从零写一个promise。 步骤一 Promise特点 1,创建时需要传递一个函数,否则会报错2,会给传入的函…...
【leetcode】寻找重复数
题目链接:寻找重复数https://leetcode.cn/problems/find-the-duplicate-number/ 方法一:快慢指针 因为只有一个数字是重复的,且一个数字正好对应一个唯一的下标,所以可以将数组抽象为一个链表,假定数组为{1,2,3,4,5,…...
LeetCode 1247. Minimum Swaps to Make Strings Equal【数学,贪心,字符串】
本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章…...
pid控制加热算法,附代码仓库
1、该项目层次化结构清晰,代码框架耦合度低,可复用性、可移植性强。 2、功能代码与底层硬件无直接关联,无需更改上层应用逻辑,只需更改接口文件,即可移植到不同的硬件平台; 3、使用lwrb开源组件、pid开源算…...
一文看懂预训练和自训练模型
说到预训练模型,不得不提迁移学习了,由于很多数据不是标签数据,人工标注非常耗时,神经网络在很多场景下受到了限制。但是迁移学习和自学习的出现,在一定程度上缓解甚至解决了这个问题。我们可以在标签丰富的场景下进行…...
(五十四)大白话索引的页存储物理结构,是如何用B+树来实现的?.md
上一次我们给大家说了主键索引的目录结构,只要在一个主键索引里包含每个数据页跟他最小主键值,就可以组成一个索引目录,然后后续你查询主键值,就可以在目录里二分查找直接定位到那条数据所属的数据页,接着到数据页里二…...
苏南建设集团网站/nba最新交易汇总
深海才会有鲸鱼 首先,在此,感怀毛星云先生,虽并无交集,但若曾我有幸认识你的话,我想我一定是你的忠实的粉丝,你一定是我的追逐的榜样。 听到这样的消息真的好惋惜,如此勤奋、聪颖、执着且有梦想…...
东莞微信网站建设怎样/百度知道合伙人答题兼职
作为过来人这个报错之前出现过好多次,但还是记录一下怎么解决这个问题 删除node-modules(快速删除node-modules之前有做记录),然后在重新instll 一遍就好了...
建设官方网站的请示/湖南网站排名
1. DOM复习 DOM:document object model 文档对象模型或文档树模型。 1.1 节点分类 DOM中一共有5个节点类型,而现在我们常用的有三种:标签(元素)节点,属性节点,文本节点。 我们可以通过nodeType…...
坪地网站建设价格/电子商务seo
1、监控过程将向项目提供什么好处? A.通过观察和衡量项目绩效来识别偏差 B.通过观察和衡量项目绩效向变更控制委员会(CCB)识别输入 C.通过观察和衡量项目绩效来更新过程改进计划。 D.通过观察和衡量项目绩效来更新项目管理计划。 答案:A。解析:4.5监…...
删除网站留言板功能/app优化推广
变量是保存存储值的内存位置。也就是说,当创建一个变量时,可以在内存中保留一些空间。 基于变量的数据类型,解释器分配内存并决定可以存储在保留的存储器中的内容。 因此,通过为变量分配不同的数据类型,可以在这些变量…...
php做电商网站的难点/百度推广关键词越多越好吗
熊猫帮帮主cnblogs 2018/1/25 问题描述:在Windows下将中文文件名的文件打成压缩包,在Linux下解压出现文件名乱码。 问题原因:Windows和Linux下采用不同中文编码格式,导致在Linux下解压时出现文件名乱码。 解决方案:在命…...