Java 为什么 Hibernate 会抛出 org.hibernate.exception.LockAcquisitionException?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25097957/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does Hibernate throw org.hibernate.exception.LockAcquisitionException?
提问by Abdelhafid
I have this method :
我有这个方法:
mymethod(long id){
Person p = DAO.findPerson(id);
Car car = new Car();
car.setPerson(p);
p.getCars().add(car);
DAO.saveOrUpdate(car);
DAO.saveOrUpdate(p);
DAO.delete(p.getCars().get(0));//A person have many cars
}
Mapping :
映射:
Person.hbm.xml
人员.hbm.xml
<!-- one-to-many : [1,1]-> [0,n] -->
<set name="car" table="cars" lazy="true" inverse="true">
<key column="id_doc" />
<one-to-many class="Car" />
</set>
<many-to-one name="officialCar"
class="Car"
column="officialcar_id" lazy="false"/>
Cars.hbm.xml
汽车.hbm.xml
<many-to-one name="person" class="Person"
column="id_person" not-null="true" lazy="false"/>
This method works well for a single thread, and on multiple threads, gives me an error:
此方法适用于单个线程,在多个线程上,给我一个错误:
02/08/2014 - 5:19:11 p.m. - [pool-1-thread-35] - WARN - org.hibernate.util.JDBCExceptionReporter - SQL Error: 60, SQLState: 61000
02/08/2014 - 5:19:11 p.m. - [pool-1-thread-35] - ERROR - org.hibernate.util.JDBCExceptionReporter - ORA-00060: deadlock detection while waiting for a resource
?
02/08/2014 - 5:19:11 p.m. - [pool-1-thread-35] - WARN - org.hibernate.util.JDBCExceptionReporter - SQL Error: 60, SQLState: 61000
02/08/2014 - 5:19:11 p.m. - [pool-1-thread-35] - ERROR - org.hibernate.util.JDBCExceptionReporter - ORA-00060: deadlock detection while waiting for a resource
?
02/08/2014 - 5:19:11 p.m. - [pool-1-thread-35] - ERROR - org.hibernate.event.def.AbstractFlushingEventListener - Could not synchronize database state with session
org.hibernate.exception.LockAcquisitionException: Could not execute JDBC batch update
AOP Transaction :
AOP 交易:
<tx:advice id="txAdviceNomService" transaction-manager="txManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
<tx:method name="getAll*" read-only="true" propagation="SUPPORTS" />
<tx:method name="find*" read-only="true" propagation="SUPPORTS" />
</tx:attributes>
</tx:advice>
NB : When i add Thread.sleep(5000) after update, it is ok. But this solution is not clean.
注意:当我在更新后添加 Thread.sleep(5000) 时,就可以了。但是这个解决方案并不干净。
采纳答案by Abdelhafid
I have Cars -> (1 -n) places. And i have a foreign key in the table place (id_car). This foreign key dont have an index. When i add an index to this foreign key, my problem is resolved.
我有汽车 -> (1 -n) 个地方。我在表位置(id_car)中有一个外键。这个外键没有索引。当我向这个外键添加索引时,我的问题就解决了。
Refer to This Answer
参考这个答案
回答by Vlad Mihalcea
According to your mapping, the sequence of operations should look like this:
根据您的映射,操作顺序应如下所示:
Person p = DAO.findPerson(id);
Car car = new Car();
car.setPerson(p);
DAO.saveOrUpdate(car);
p.getCars().add(car);
Car firstCar = p.getCars().get(0);
firstCar.setPerson(null);
p.getCars().remove(firstCar);
if (p.officialCar.equals(firstCar)) {
p.officialCar = null;
p.officialCar.person = null;
}
DAO.delete(firstCar);
An updateor a deletemeans acquiring an exclusive lock, even on READ_COMMITTEDisolation level.
的更新或删除装置获取独占锁,即使在READ_COMMITTED隔离级别。
If another transaction wants to update the same row with the current running transaction (which already locked this row in question) you won't get a deadlock, but a lock acquisition timeoutexception.
如果另一个事务想要使用当前正在运行的事务(已经锁定了该行)更新同一行,您将不会遇到死锁,而是会遇到锁获取超时异常。
Since you got a deadlock, it means you acquire locks on multiple tables and the lock acquisitions are not properly ordered.
由于您遇到了死锁,这意味着您在多个表上获取了锁,并且锁获取的顺序不正确。
So, make sure that the service layer methods set the transaction boundaries, not the DAO methods. I see you declared the getand findmethods to use SUPPORTED, meaning they will use a transaction only if one is currently started. I think you should use REQUIRED for those as well, but simply mark them as read-only = true
.
因此,请确保服务层方法设置事务边界,而不是 DAO 方法。我看到你声明了get和find方法来使用 SUPPORTED,这意味着只有当一个事务当前启动时它们才会使用一个事务。我认为您也应该对这些使用 REQUIRED,但只需将它们标记为read-only = true
.
So make sure the transaction aspect applies the transaction boundary on the "mymethod" and not on the DAO ones.
因此,请确保事务方面将事务边界应用于“mymethod”而不是 DAO 的。