【问题标题】:Hibernate session not synchronize when deadlock detected检测到死锁时休眠会话不同步
【发布时间】:2018-02-23 08:24:05
【问题描述】:

我有以下方案来保存我的对象

// Started transaction
User objUser = getUser("123");// get user from DB
objUser.set(...)
.
.
UserAddress objUserAddress = objUser.getUserAddress();
objUserAddress.set(..);
.
.
hibernateSession.flush(); //#Line 1
hibernateSession.saveOrUpdate(objUserAddress); //#Line 2
hibernateSession.flush(); //#Line 3
hibernateSession.saveOrUpdate(objUser); //#Line 4
// Commit transaction

这里是用户和地址类之间的休眠映射

<class name="com.service.core.bo.impl.User" table="USERS">
.
.
<many-to-one name="userAddress" class="com.service.core.bo.impl.UserAddress"
        column="ADDRESS_ID" not-null="false" unique="true" cascade="save-update"
        lazy="false" />
.
.
</class>

有时我在#Line 1 收到死锁。这是异常堆栈。

[2017-12-12 11:15:02.131 GMT] WARN [] [] [] [] [] [] [] [] [] http-bio-8280-exec-14 org.hibernate.util.JDBCExceptionReporter - SQL Error: 60, SQLState: 61000
[2017-12-12 11:15:02.131 GMT] ERROR [] [] [] [] [] [] [] [] [] http-bio-8280-exec-14 org.hibernate.util.JDBCExceptionReporter - ORA-00060: deadlock detected while waiting for resource

[2017-12-12 11:15:02.131 GMT] ERROR [] [] [] [] [] [] [] [] [] http-bio-8280-exec-14 org.hibernate.event.def.AbstractFlushingEventListener - Could not synchronize database state with session
org.hibernate.exception.LockAcquisitionException: Could not execute JDBC batch update
        at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:87)
        at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
        at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:253)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:266)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:172)
        at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
        at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
        at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
        at sun.reflect.GeneratedMethodAccessor706.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
       .
       .
Caused by: java.sql.BatchUpdateException: ORA-00060: deadlock detected while waiting for resource
        at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:12296)
        at oracle.jdbc.driver.OracleStatementWrapper.executeBatch(OracleStatementWrapper.java:246)
        at sun.reflect.GeneratedMethodAccessor553.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at oracle.ucp.jdbc.proxy.StatementProxyFactory.invoke(StatementProxyFactory.java:353)
        at oracle.ucp.jdbc.proxy.PreparedStatementProxyFactory.invoke(PreparedStatementProxyFactory.java:178)
        at com.sun.proxy.$Proxy66.executeBatch(Unknown Source)
        at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
        at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:246)
        ... 71 more

问题是,这个错误是不一致的。这可能在一天内发生一次或多次,而其他一天则没有。 不知道为什么flush() 导致Could not synchronize database state with sessionORA-00060: deadlock detected while waiting for resource。我为会话状态找到了一些链接,如 Could not synchronize database state with session,但我的实际原因是死锁,如上述异常。

【问题讨论】:

    标签: java hibernate hibernate-mapping database-deadlocks


    【解决方案1】:

    无法将数据库状态与会话同步是一个一般性的休眠错误,可能有多个根本原因。 您应该关注的错误是:

    ORA-00060:在等待资源时检测到死锁

    这是 Oracle 特有的,当从多个连接对同一数据(数据库中的行)进行更新时会发生这种情况。每当 Oracle(实际上几乎是任何数据库)更新一行时,它都会在更新期间锁定它。如果在锁定时在同一行上尝试另一个更新,则会发生此错误。 以下是 Oracle 官方给出的错误解释:

    ORA-00060: 在等待资源时检测到死锁

    原因:事务在等待资源时相互死锁。

    操作:查看跟踪文件以查看涉及的事务和资源。必要时重试。

    解决此问题的一种方法是使用版本控制:

    https://www.intertech.com/Blog/versioning-optimistic-locking-in-hibernate/

    这会在表中添加一个版本列,该列会在行更新时自动递增。在更新之前检查版本,如果它高于预期的版本,则更新甚至不会更新并引发特定错误,您可以处理。通常处理涉及从数据库中重新加载该实体的信息,将其值重置为您想要的值,然后保存。

    【讨论】:

    • 感谢并为延迟回复道歉。你是正确的,当两个资源试图同时更新时发生了死锁。但就我而言,我仅在 flush() 方法上遇到此异常。
    • 是的,这很正常,因为只有这样您所做的更改才会真正应用于数据库。 saveOrUpdate() 不会做数据库操作,调用flush()时一切都完成了。
    猜你喜欢
    • 1970-01-01
    • 2010-11-14
    • 2012-02-10
    • 1970-01-01
    • 1970-01-01
    • 2017-06-13
    • 2016-12-19
    • 2017-11-15
    • 2012-06-02
    相关资源
    最近更新 更多