Spring @Transactional死锁

时间:2011-10-30 20:24:20

标签: mysql spring deadlock spring-transactions

我有以下设置。

  • Spring 3.0.5
  • Hibernate 3.5.6
  • MySql 5.1

要通过Hibernate在DB中保存记录,我有以下工作流程

  1. 将JSON {id:1,name:"test",children:[...]}发送到Spring MVC App并使用Jackson将其转换为对象图(如果它是现有实例,则JSON具有DB集中记录的正确ID

  2. 通过服务层调用将对象保存在DB中(详情如下)

    • 服务层界面SomeObjectService的保存功能在readOnly=false和传播REQUIRED

    • 上有@Transactional注释
    • 此服务层SomeObjectServieImpl的实现调用DAO保存 方法

    • DAO通过调用hibernate的合并来保存新数据,例如: hibernateTempate().merge(someObj)

    • hibernate merge首先通过SELECT

    • 从数据库加载对象
    • 我有一个连接到spring的EntityListener(我使用了这种技术Spring + EntityManagerFactory +Hibernate Listeners + Injection)并听取了@PostLoad

    • 侦听器使用LockingServie更新someObject的一个字段以将其设置为已锁定(此实际上只应在通过Hibernate HQL加载someObject时发生,SQL或Criteria调用,但也会在合并时调用)

    • LockingServie有一个lock(someObj,userId)函数,该函数也注明了@Transactional readOnly=falseREQUIRED

    • 通过调用Query query = sess.createQuery("update someObj set lockedBy=:userId");然后进行更新 query.executeUpdate();

    • 在合并加载了数据后,它开始更新someObject并插入相关的子项(< = exacely here 死锁发生

  3. 将JSON结果(这也包括新创建的对象ID)返回给客户端。

  4. 首先,问题出现在我身上

    1. 记录在事务中加载
    2. 然后在另一个(内部)交易中被改变
    3. 然后应该再次使用外部事务的数据进行更新,但由于它已被锁定而无法更新。
    4. 我可以通过MySQL看到

      SHOW OPEN TABLES 
      

      子表(是对象图的一部分)被锁定。

      有趣的事实是,someObj 表上不会出现死锁,而是代表孩子的表。

      我有点迷失在这里。任何帮助都非常受欢迎。

      顺便说一句,BTW可能会isolation级别让我摆脱这个问题吗?

2 个答案:

答案 0 :(得分:1)

我最终使用了@ Bozho的HibernateExtendedJpaDialect

在此解释>> Hibernate, spring, JPS & isolation - custom isolation not supported

将隔离设置为 READ_UNCOMMITED

@Transactional(readOnly = false, propagation = Propagation.REQUIRED, isolation=Isolation.READ_UNCOMMITTED)
public Seizure merge(Seizure seizureObj);

我知道这不是一个非常好的解决方案,但至少这解决了我的问题。

如果有人想要详细说明,请询问......

答案 1 :(得分:0)

我不知道问题的解决方案,但我没有事务锁定方法。如果您需要手动锁定某些内容,请在另一种事务服务方法中进行。