环境:
我们有一个部署在JBoss 4.2.3.GA服务器上的应用程序,它使用Hibernate 3.4和JTA1.0。
有一个导入程序,它创建或更新某些实体,然后导入一些数据。由于几个原因,大部分导入是在新事务中完成的,在每个事务中,在外部事务中创建/更新的实体可能会再次更新。
调用序列类似于以下伪代码:
Service1:
//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
}Service2:
@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按顺序运行。
问题
从上述情况看,出现了以下问题:
(谢谢你阅读这一切:)
更新1:
因为我不是代码的作者,所以我也必须深入研究它。到目前为止,Hibernate中没有任何显式锁定的提示,因此只在向数据库resp写入时使用数据库锁。打开数据库连接时。
我们使用的是自动刷新,因此在某些情况下,T1可能在T2尝试相同之前打开连接,但是T1无法提交和关闭连接,因为它一直挂起直到T2提交。因此,由于T1的刷新,数据库所需要的锁也不能在T2刷新之前释放。
使用手动刷新并不是一个解决方案,因为如果T2在T1之前提交,那么我们就会丢失更新,但是对实体的更改正好相反。我知道这是设计中的一个缺陷,我们需要修复它,但我也想确认我们的假设是正确的,以便提供一个合理的解决方案:)
发布于 2013-03-25 18:19:58
我会尽力给出一些线索,
你说那个表是锁定的,我不知道你在做什么,it.Hibernate默认不会获得任何锁。您需要明确地告诉它这样做,看见。即使在这里,您也不是在表上获得锁,而是在单行上获得锁。只有在使用悲观锁定且这两个事务都需要对同一行进行锁定时,您的假设才能成立。
如果您没有使用悲观锁定,那么当T1尝试提交时,您应该得到乐观锁异常。因此,您的场景可能导致相同的对象,而不是由两个事务更新。
如果不进行调试,不知道“创建”和“更新”中发生了什么,就很难回答您的问题。
https://stackoverflow.com/questions/15620353
复制相似问题