我继承了一个系统,它使用Spring MVC和Hibernate存储到DB2数据库中。最近它开始出现DB2报告的死锁问题,所以我一直在调试它。我不是Spring或Hibernate专家,但我对这两种语言都了解一些。
代码的结构如下:
controller -> service -> one or more DAO classes that performs the updates
在出现问题的情况下,控制器调用带有@Transactional
和@Override
注释的服务方法。该服务转到用@Repository
注释的DAO类,并调用用@Transactional
和@Override
注释的多个方法。这就是代码的结构。
一个控制器调用一个服务方法。服务方法调用多个DAO方法。大多数DAO方法都被标记为@Transactional
和@Override
。有几个在@Transactional
中有REQUIRES_NEW。而且,在每个DAO方法中,SessionFactory.getCurrentSession()
都会获取Session
。
第一个问题:使用这种方法,事务从哪里开始,最终提交在哪里?那么回滚呢?所有这些都没有显式编码。
当其中一个方法更新了一条记录,然后随后的方法删除了该记录时,就会出现死锁。如果您想知道为什么有人想要这样做,那么更新将添加想要删除记录中信息的人的用户id,以便存储的进程可以将其保存到另一个表中。然后,第二个方法调用删除该记录。
最初的程序员试图将REQUIRES_NEW添加到@Transactional
中,认为一个新的事务将确保更新会发生。但是死锁仍然以不规则的时间间隔发生。
我尝试将更新更改为本机SQL调用,但Hibernate不允许我启动另一个事务,因为一个事务已经打开。
这里有没有人有什么建议?
发布于 2020-06-18 02:52:17
当一个方法(调用链中的哪个类或方法本身首先用@Transactional
注释)从外部调用(它必须从类的外部调用,因为注释“创建”了一个代理)时,事务就开始了。链中具有默认传播级别的任何其他带注释的类/方法都将加入该事务。当调用带有事务标记为REQUIRES_NEW
的方法时,父事务将被挂起(如果存在),并且新事务开始。请注意,如果您从同一个类中的其他方法调用带注释的方法,那么它将不会通过代理,因此它与您删除注释相同。提交发生在启动事务返回的方法之后。与回滚相同,抛出异常后会回滚。死锁可能来自不同的地方,即使你有代码也很难找出来。例如,它可能来自update和存储过程,试图锁定某些行,以及发生循环等待等。
我有一个天真的图像,背景中发生了什么。有两个类ui和服务。该服务被注释为@Transactional
。Spring创建代理,所有来自外部的调用都要经过它。在调用真正的方法之前,它会启动事务,然后提交。
https://stackoverflow.com/questions/62435453
复制相似问题