web-dev-qa-db-ja.com

Hibernateがorg.hibernate.exception.LockAcquisitionExceptionをスローするのはなぜですか?

私はこの方法を持っています:

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)を追加しても問題ありません。ただし、このソリューションはクリーンではありません。

11
Abdelhafid

車->(1 -n)の場所があります。そして、テーブルの場所(id_car)に外部キーがあります。この外部キーにはインデックスがありません。この外部キーにインデックスを追加すると、問題が解決します。

この回答 を参照してください

0
Abdelhafid

マッピングによると、操作のシーケンスは次のようになります。

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);

updateまたはdeleteexclusive lockを取得することを意味しますREAD_COMMITTED 分離レベルでも。

別のトランザクションが現在の実行中のトランザクション(問題のこの行を既にロックしている)で同じ行を更新したい場合、デッドロックは発生しませんが、lock Acquisition timeout例外が発生します。

デッドロックが発生したため、複数のテーブルでロックを取得し、ロックの取得が適切に順序付けられていないことを意味します。

そのため、サービスレイヤーメソッドが、DAOメソッドではなく、トランザクション境界を設定するようにしてください。 SUPPORTEDを使用するためにgetおよびfindメソッドを宣言したことを意味しますトランザクションは、現在開始されている場合にのみ使用されます。これらにもREQUIREDを使用する必要があると思いますが、単にread-only = true

そのため、トランザクションの側面では、DAOのトランザクションではなく、「mymethod」でトランザクション境界を適用するようにしてください。

10
Vlad Mihalcea