web-dev-qa-db-fra.com

Pourquoi Hibernate lève org.hibernate.exception.LockAcquisitionException?

J'ai cette méthode:

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
}  

Cartographie:

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"/>   

Cette méthode fonctionne bien pour un seul thread, et sur plusieurs threads, me donne une erreur:

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

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: lorsque j'ajoute Thread.sleep (5000) après la mise à jour, c'est ok. Mais cette solution n'est pas propre.

11
Abdelhafid

J'ai des voitures -> (1 -n) places. Et j'ai une clé étrangère à la place de la table (id_car). Cette clé étrangère n'a pas d'index. Lorsque j'ajoute un index à cette clé étrangère, mon problème est résolu.

Reportez-vous à Cette réponse

0
Abdelhafid

Selon votre mappage, la séquence des opérations devrait ressembler à ceci:

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

Un mise à jour ou un supprimer signifie acquérir un verrouillage exclusif , même le READ_COMMITTED niveau d'isolement.

Si une autre transaction veut mettre à jour la même ligne avec la transaction en cours d'exécution (qui a déjà verrouillé cette ligne en question), vous n'obtiendrez pas un blocage, mais une exception lock acquisition timeout.

Étant donné que vous avez un blocage, cela signifie que vous acquérez des verrous sur plusieurs tables et que les acquisitions de verrous ne sont pas correctement ordonnées.

Assurez-vous donc que les méthodes de la couche de service définissent les limites des transactions, pas les méthodes DAO. Je vois que vous avez déclaré les méthodes get et find pour utiliser SUPPORTED, ce qui signifie ils utiliseront une transaction uniquement si une est en cours de démarrage. Je pense que vous devriez également utiliser REQUIS pour ceux-ci, mais marquez-les simplement comme read-only = true.

Assurez-vous donc que l'aspect transaction applique la limite de transaction sur la "méthode mym" et non sur celles DAO.

10
Vlad Mihalcea