广告
返回顶部
首页 > 资讯 > 数据库 >事务注解(@Transactional)引起的数据覆盖故障
  • 605
分享到

事务注解(@Transactional)引起的数据覆盖故障

2024-04-02 19:04:59 605人浏览 安东尼
摘要

最近组织团队内技术培训,刘聪为分享的一个跟事务和写数据库相关的case(bug)很有代表性。用事务,要小心!一、故障现象车辆交付履约流程上两个节点(工程项目)A和B, A修改一条数据记录item(工单),然

最近组织团队内技术培训,刘聪为分享的一个跟事务和写数据库相关的case(bug)很有代表性。用事务,要小心!

一、故障现象

车辆交付履约流程上两个节点(工程项目)A和B, A修改一条数据记录item(工单),然后发消息给B,B也会对item进行修改。

故障现象,有时候(不是必现)感觉A没有成功修改item这条数据,而日志显示A修改成功了数据item!

看一下具体代码实现。下图是工程A代码,3个红框依次动作。

1、开启事务

2、修改工单记录item

3、向下游节点发送MQ消息 

事务注解(@Transactional)引起的数据覆盖故障

下图是下游消费mq消息的节点B,红框表示采用JPA技术修改数据记录item

事务注解(@Transactional)引起的数据覆盖故障

二、原因分析

这个过程总共经历5个步骤,见下图 

事务注解(@Transactional)引起的数据覆盖故障

1、节点A开启一个事务,修改数据表中某条数据item

2、A向B发送mq消息,再做些其他事情,提交事务

3、节点B,消费mq消息

4、节点B读出数据item

5、节点B在内存中修改数据item某些字段,写回数据库

注意到第1、2步骤是在一个事务中。存在一种可能,B节点收到mq消息,执行第4步骤,读取item数据后,步骤1、2的事务才完成提交。由于数据库事务隔离级别,这种情况下,第4步骤读到的数据并不是A节点在第1步写的,已经读到脏数据了。当第5步写回数据的时候,就可能造成老数据覆盖A写的新数据。

这里有两个细分场景

1、第1步、第5步修改同一个字段。这种情况,第4步骤读到脏数据 

事务注解(@Transactional)引起的数据覆盖故障

2、第1步、第5步修改不同字段。第4步读到col2字段的oldvalue,第5步目的是修改col3的值,但是采用jpa或者mybatis的一些默认写法,会把col2的oldvalue更新回数据库。

一般的ORMapping框架利用一个vo对象写数据库记录,没有修改的字段不会更新(代码里并没有改col2的值),但是第4步读取数据后,第1步对数据item进行了修改。这样默认的写库方法,会check记录的变化,然后把col2字段的值更新。这样就出现了旧值覆盖新值的问题。 

事务注解(@Transactional)引起的数据覆盖故障

三、解决办法

1、考虑到实施成本,如果修改不同的字段,不存在竞争关系。只需要在第5步写库的环节指定更新字段就能快速解决这个问题。事实上,生产环境下也是选择的这个方案临时修复。

2、解决办法1显然不够优秀。更好的做法,把第2步发mq消息从事务中拆出来,等第1步操作commit后在发mq消息。这个办法涉及到一些逻辑的梳理(业务代码里会有不少的if……else),代码的改动。这样处理仍然不够完美,第1步执行完了,第2步失败了怎么办?在这里可能需要一些额外的代码工作保证第2步执行成功。

3、如果业务压力不大,也可以考虑从数据库的事务隔离级别方面入手来解决这个问题。

4、业务上,第1步到第5步如果需要强一致,了解一下分布式事务

https://www.jianshu.com/p/16b1baf015e8

您可能感兴趣的文档:

--结束END--

本文标题: 事务注解(@Transactional)引起的数据覆盖故障

本文链接: https://www.lsjlt.com/news/48452.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作