我有这个方法:
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
}
映射:
Person.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
<many-to-one name="person" class="Person"
column="id_person" not-null="true" lazy="false"/>
此方法适用于单个线程,并且在多个线程上,给出了一个错误:
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交易:
<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>
注意:当我在更新后添加Thread.sleep(5000)时,没关系。但这个解决方案并不干净。
答案 0 :(得分:9)
根据您的映射,操作顺序应如下所示:
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);
更新或删除意味着即使在exclusive lock隔离级别上也会获得READ_COMMITTED。
如果另一个事务想要使用当前正在运行的事务更新同一行(已经锁定了该行),则不会出现死锁,而是锁定获取超时异常。
由于您遇到了死锁,这意味着您获取了多个表上的锁定,并且锁定采集未正确排序。
因此,请确保服务层方法设置事务边界,而不是DAO方法。我看到您声明获取和查找方法以使用SUPPORTED,这意味着只有当前启动时才会使用交易。我认为你也应该使用REQUIRED,但只需将它们标记为read-only = true
。
因此,请确保事务方面在“mymethod”上应用事务边界而不在DAO上应用事务边界。
答案 1 :(得分:0)
我有汽车 - &gt; (1-n)个地方。 我在表格中有一个外键(id_car)。这个外键没有索引。 当我为这个外键添加一个索引时,我的问题就解决了。
请参阅This Answer