Spring @Transactional 死锁
我有以下设置。
- Spring 3.0.5
- Hibernate 3.5.6
- MySql 5.1
要通过 Hibernate 在数据库中保存记录,我有以下工作流程
send JSON
{id:1,name:"test",children:[...] }
到 Spring MVC 应用程序并使用 Jackson 将其转换为对象图(如果它是现有实例,则 JSON 具有数据库集中记录的正确 ID通过服务层调用将对象保存在DB中(详细信息如下)
服务层接口
SomeObjectService
的save函数,上面有@Transactional注解,readOnly=false
和PropagationREQUIRED
< /p>该服务层的实现
SomeObjectServieImpl
调用DAO保存 方法DAO 通过调用 hibernate 的合并来保存新数据,例如
hibernateTempate().merge(someObj)
hibernate
merge
首先通过SELECT
从数据库加载对象我有一个连接到 spring 的 EntityListener (我使用了这种技术 Spring + EntityManagerFactory +Hibernate Listeners + Injection)并监听
@PostLoad
侦听器使用
LockingServie
更新someObject
的一个字段,将其设置为锁定(此实际上应该仅在someObject
通过 Hibernate HQL、SQL 或 Criteria 调用加载,但也会在合并时调用)LockingServie
有一个函数lock(someObj,userId)
,它也用 @Transactional 和readOnly=false
进行注释,并且必需
更新是通过调用
Query query = sess.createQuery("update someObj setlockedBy=:userId");
进行的,然后query.executeUpdate();
合并加载数据后,首先更新
someObject
并插入相关子对象(<=这里正是死锁发生的点)< /p>
将 JSON 结果(这也包括新创建的对象 ID)返回给客户端。
对我来说,问题似乎是,首先
- 记录被加载到一个事务中
- ,然后在另一个(内部)事务中被更改
- ,然后应该使用外部事务的数据再次更新,但由于它被锁定而无法更新。
我可以通过 MySQL 看到
SHOW OPEN TABLES
子表(对象图的一部分)被锁定。
有趣的事实是,死锁不会发生在 someObj 表上,而是发生在代表子项的表上。
我在这里有点迷失了。非常欢迎任何帮助。
顺便说一句,也许可以 隔离级别能让我摆脱这个问题吗?
I have the following setup.
- Spring 3.0.5
- Hibernate 3.5.6
- MySql 5.1
To save a record in the DB via Hibernate I have the following workflow
send JSON
{id:1,name:"test",children:[...]}
to Spring MVC App and use Jackson to transform it into an object graph (if it is an existing instance the JSON has the proper ID of the record in the DB setsave the object in DB via service layer call (details below)
the save function of service layer interface
SomeObjectService
has the @Transactional annotation on it withreadOnly=false
and PropagationREQUIRED
the implementation of this service layer
SomeObjectServieImpl
calls the DAO save
methodthe DAO saves the new data via a call of hibernate's merge e.g.
hibernateTempate().merge(someObj)
hibernate
merge
loads the object first from the DB viaSELECT
I have a EntityListener who is wired to spring (I used this technique Spring + EntityManagerFactory +Hibernate Listeners + Injection) and listens to
@PostLoad
The listener uses a
LockingServie
to updates one field ofsomeObject
to set it as locked (this should actually only happen whensomeObject
is loaded via Hibernate HQL,SQL or Criteria calls but gets called also on merge)the
LockingServie
has a functionlock(someObj,userId)
which is also annotated with @Transactional withreadOnly=false
andREQUIRED
the update happens via a call of
Query query = sess.createQuery("update someObj set lockedBy=:userId");
and thenquery.executeUpdate();
after merge has loaded the data it start with updating
someObject
and inserting relevant children (<= exacely here is the point where the deadlock happens)
return JSON result (this also includes the newly created object ID) back to client.
The problem seems for me that first
- the record gets loaded in a transaction
- then gets changed in another (inner-)transaction
- and then should get updated again with the data of the outer transaction but can't get updated because it is locked.
I can see via MySQL's
SHOW OPEN TABLES
that a child table (that is part of the object graph) is locked.
Interesting fact is that the deadlock doesn't occur on the someObj table but rather on a table that represents a child.
I am a bit lost here. Any help is more than welcome.
BTW can maybe the isolation level get me out of this problem here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我不知道问题的解决方案,但我不会有事务锁定方法。如果您确实需要手动锁定某些内容,请在另一个事务服务方法中进行锁定。
I don't know the solution to the problem, but I would not have a transactional lock method. If at all you need to lock something manually, make it within another transactional service method.
我最终使用了 @Bozho 的
HibernateExtendedJpaDialect
,其解释如下>>
Hibernate、Spring、JPS 和 Hibernate隔离 - 不支持自定义隔离
将隔离设置为READ_UNCOMMITED
我知道这不是一个很好的解决方案,但至少这解决了我的问题。
如果有人想要详细的描述,请询问...
I ended up using @Bozho's
HibernateExtendedJpaDialect
which is explained here >>
Hibernate, spring, JPS & isolation - custom isolation not supported
To set the isolation to READ_UNCOMMITED
Not a very nice solution I know but at least this solved my problem.
If somebody wanna have a detailed description please ask...