我有以下方案来保存我的对象
// 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
这是User和Address类之间的hibernate映射
<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 session
和ORA-00060: deadlock detected while waiting for resource
的原因。我找到了一些类似Could not synchronize database state with session的链接用于会话状态,但我的实际原因是死锁,如上所述。
答案 0 :(得分:2)
无法将数据库状态与会话同步是一个通用的hibernate错误,可能有多个根本原因。 您应该关注的错误是:
ORA-00060:在等待资源时检测到死锁
这是Oracle特定的,当从多个连接发生对相同数据(数据库中的行)的更新时会发生这种情况。每当Oracle(实际上几乎任何数据库)更新一行时,它会在更新期间锁定它。如果在锁定时在同一行上尝试另一次更新,则会发生此错误。 以下是Oracle的官方错误解释:
ORA-00060:在等待资源时检测到死锁
原因:交易在等待资源时相互死锁。
操作:查看跟踪文件以查看涉及的事务和资源。必要时重试。
解决此问题的一种方法是使用版本控制:
https://www.intertech.com/Blog/versioning-optimistic-locking-in-hibernate/
这会向表中添加一个版本列,该行会在更新行时自动递增。在更新之前,将检查版本,如果版本高于预期版本,则更新甚至不会更新,并且会抛出特定错误,您可以处理。通常,处理涉及从该实体的数据库重新加载信息,将其值重置为您想要的值然后保存。