当前位置: 首页 > 知识库问答 >
问题:

JTA嵌套事务锁

刘焱
2023-03-14

环境:

我们有一个应用程序部署在 JBoss 4.2.3.GA 服务器中,它使用Hibernate 3.4 和 JTA 1.0。

有一个导入器创建或更新某些实体,然后导入一些数据。由于多种原因,大部分导入是在新事务中完成的,在每个事务中,在外部事务中创建/更新的实体可能会再次更新。

调用序列类似于以下伪代码:

服务1:

//container managed transaction T1 is started here
import() {    

  A a = ... ;//new or read from database
  if( isNew( a ) ) { 
     create(a);
  } else {
     update(a);
  }

  Service1 s = ...; //injected or looked up
  for( D d : someDataList ) {  
     //nested transaction T2 is started due to this call, T1 should be suspended
     s1.importData(d);   

     //nested transaction T2 should have been committed here
  }

服务2:

  @TransactionAttribute(REQUIRES_NEW)
  importData(D d) {
    A a = ...; //get the corresponding A instance and update as needed
    update(a);
    //other stuff such as importing d
  }

问题:

现在的问题是,我们最终会遇到一个竞争条件,有几个事务试图锁定相同的表,但到目前为止,我们既无法重现问题,也无法确定真正的原因。

不过,我们有一些假设:

由于在 T1 期间更新了某些实体,因此转换会获取一些数据库锁。然后,T1 被挂起,因为 T2 已启动,而 T2 又会尝试获取相同的数据库锁,因此被阻止。T2 最终会超时,然后 T1 可以正常完成并释放锁。

可能的解决方案?:

到目前为止,似乎只有一个可能的解决方案:将T1中的所有更新打包到另一个事务T1*中(可能完全跳过T1),并让T1*和T2按顺序运行。

如果业务案例允许这样做,这是否是一个合理的解决方案(我不确定,因为我自己没有实现该业务案例)?

可能还有其他解决方案,如果有,请提供一些提示。然而,我对此表示怀疑,因为似乎T1必须在T2尝试获取锁之前释放锁,因此基本上使T1和T2按顺序运行。

问题

从上面可以看出以下问题:

  • 我们的假设是否正确,即T1是否持有T2也需要的锁,并且由于它被挂起而无法释放?
  • 我上面描述的解决方案是唯一的方法,还是没有其他方法没有手动事务划分?

感谢您阅读本文:)

更新1:

因为我不是代码的作者,所以我也必须深入研究它。到目前为止,Hibernate中没有任何显式锁定的提示,因此AFAIK Hibernate只在写入数据库时使用数据库锁。当数据库连接打开时。

我们使用的是自动刷新,因此在某些情况下,T1 可能会在 T2 尝试相同的连接之前打开连接,但 T1 无法提交并关闭连接,因为它在 T2 提交之前处于挂起状态。因此,数据库似乎由于 T1 的刷新而获得的锁也无法在 T2 刷新之前释放。

使用手动刷新不是一个解决方案,因为如果T2在T1之前提交,我们就会丢失更新,但对实体的更改则相反。我知道这是设计中的一个缺陷,我们需要修复它,但我也想确认我们的假设是正确的,以便提供合理的修复:)

共有1个答案

史绍晖
2023-03-14

我会尽力提供一些线索,

你说桌子被锁了。我不知道你在哪里做这件事。默认情况下,Hibernate不会获取任何锁。您需要明确告诉它这样做,请参见。即使在这里,您也不是在表上获得锁,而是在单行上获得锁。只有当您使用悲观锁定并且两个事务都需要在同一行上锁定时,您的假设才能成立。

如果您没有使用悲观锁定,那么在T1尝试提交时应该会出现乐观锁定异常。所以,您的场景可能会导致同一个对象不被两个事务更新。

如果不进行调试,并且不知道“创建”和“更新”中发生了什么,就很难回答您的问题。

 类似资料:
  • 问题内容: JTA为什么不支持嵌套事务?是因为实现它们的复杂性(我对此表示怀疑)还是某些设计原则? 问题答案: (正如@Piotr Nowicki指出的那样,JTA 确实 允许嵌套事务,但这不是强制性的可选操作。) 为什么?这是无法确定地回答的问题之一,除非您是做出决定时“在房间里”的人之一。 将嵌套事务作为规范的一部分包括在内可能是固有的复杂性。或当时明显的复杂性;即他们不知道他们知道如何做一个

  • 据我所知,当您尝试在提交前一个事务之前开始一个事务时,会发生这种异常。然而,我不明白为什么在我的情况下会有这种例外。 我有一个Web应用程序与以下servlet: 这是我的Compte对象: 这是我的DAO的接口: 这就是它的实施: 另外,这是我的Spring配置: 关联的应用程序。属性文件包含以下行: 最后,我有以下servlet过滤器,从这里开始事务: 这是在网络上映射的。如下所示的xml文件

  • 问题内容: 我正在研究应用数据库架构更新的脚本。我已经使用start transaction / commit设置了所有的SQL更新脚本。我在命令行上将这些脚本传递给psql。 现在,我需要在一个事务中同时应用多个脚本。到目前为止,我想出的唯一解决方案是从原始脚本集中删除启动事务/提交,然后将它们卡在新的启动事务/提交块中。我正在编写perl脚本来即时执行此操作。 实际上,我想要嵌套事务,但是我无

  • 我在tomcat服务器中使用具有多个数据源配置的JTA原子事务。有时我会遇到以下异常: JTA事务意外回滚(可能是由于超时);嵌套的异常是javax。交易回滚异常:事务被设置为仅回滚 出现这种异常的原因是什么?

  • 并用@Transactional注释了具体类。 我们使用Jboss应用服务器支持通过JNDI与MQ集成。这里的问题是,如果监听器中的任何层有任何异常,则整个事务不会回滚,消息也不会移动到退出队列。很明显,当我们使用Hibernate事务管理器时,它不知道其他资源,如JMS事务。 我可以安全地用JTA事务替换它吗,因为Jboss将处理整个事务管理?这样做是否有任何可预见的风险?

  • 我有一种情况,我必须提交一部分代码作为它自己的事务。 我已经创建了一个表: 以及plpython3u语言中的函数: 第一种情况: 表中的条目正确:1、2、4 第二种情况: 表中的值未填充 我希望或应该添加到表 中,但出乎意料的是没有插入任何值。我想象函数打开了一个新的子事务,它不应该依赖于父事务。如果我是对的,请告诉我。 Postgres中是否存在自主交易?或者我必须修改我的plpython3u函