2017-09-30 2 views
0

Nous observons un comportement étrange dans nos transactions de base de données - elles ne se comportent pas de manière atomique. Nous utilisons MySQL 5.6.25 Innodb, Eclipselink 2.5.2 comme fournisseur JPA et HikariCP 2.6.2 comme pool de connexions.Comportement non-atomique Eclipselink- Les transactions DB sont à moitié validées

Ce problème se produit lorsque Eclipselink ne parvient pas à acquérir une connexion du pool au cours d'un appel entityManager.flush. Pendant un certain temps, nous avons avalé cette exception parce que l'entrée à une table particulière était faite sur la base du meilleur effort - une sorte de mode d'audit que vous pouvez dire. Cependant, cela a conduit au cas où seule une partie de la transaction a été engagée - sur 5, seules 1,2 ou 3 entrées ont été conservées.

Pour être sûr, voici le déroulement des événements

tx.begin(); 
    em.persist(entity1); 
    try{ 
     em.persist(entity2); 
     em.flush(); ---> this is where connection acquisition fails. 
    } catch(Throwable tx){ 
    //do nothing, except log. 
    } 
    em.persist(entity3); 
    em.flush(); 
    em.persist(entity4); 
    em.flush(); 
    em.persist(entity5); 
    em.flush(); 

    em.persist(entity6); 
    tx.commit(); 

Nous voyons des transactions engagées jusqu'à entity3, entity4, entity5, lors de l'acquisition de connexion échoue à nouveau à un moment donné Quintes plus tard. Est-ce que quelqu'un peut indiquer comment cela se passe exactement?

+0

différents backends mysql ont un comportement différent, certains n'ont pas de transactions ACID. Ce que Vous utilisez (innodb, myisam etc) –

+0

Innodb. Permettez-moi de mentionner cela dès le départ. – user20507

+0

Vous ne pouvez pas attraper une exception de flush et continuer avec la transaction. – Chris

Répondre

0

Le principal problème auquel vous êtes confronté est que la connexion n'est pas disponible. Les exceptions de ce type doivent conduire à une annulation de la transaction. La prise en charge de ces transactions non gérées modifiera le comportement de la transaction. L'exception au cours de la première em.flush() annule également la première em.persist(entity1) que vous ne vouliez pas perdre. Donc la solution est d'ajouter em.flush() avant le try, pour être sûr que la persistance de l'entité 1 soit garantie ou qu'elle mène à une exception qui conduira à l'annulation de la transaction complète.

Je ne recommanderais pas ce genre de solution.

Si la persistance de entity2 est facultative, vous pouvez normalement le faire dans une transaction supplémentaire, ce qui signifie que le système aura besoin (pour une courte durée) d'une connexion db supplémentaire pour cela.

Comment créer une transaction supplémentaire? Dans Ejb, vous utilisez les méthodes annotées REQUIRES_NEW. Je ne suis pas sûr du type de TransactionManagement que vous utilisez ici, mais je suis tout à fait sûr qu'il devrait y avoir la possibilité de créer une sorte de transactions séparées (à ne pas confondre avec les transactions imbriquées !!).