2012-11-21 2 views
5

J'ai donc une application avec des appels JDBC hérités que j'ai besoin de mettre à jour avec des actions JPA supplémentaires. Je dois pouvoir faire des appels JDBC et des appels JPA dans le cadre de la même transaction DB. J'utilise OpenJPA 2.1.1 et Postgres 9.1, si c'est important. Le code suivant semble fonctionner correctement: j'ai exécuté des tests de base et les instructions JDBC et JPA s'exécutent; une erreur dans l'une ou l'autre entraîne la non-réalisation de la paire d'instructions (par exemple, elles font partie de la même transaction DB). Y a-t-il des problèmes avec ce que je ne vois pas - une bonne pratique que je viole, ou une autre raison pour laquelle je ne peux pas réutiliser l'objet Connection de cette manière?Combinaison des actions JPA et JDBC dans une transaction

EntityManager em = _em; //acquired from OpenJPA 
em.getTransaction().begin(); 
Connection conn; 
try { 
    OpenJPAEntityManager oem = (OpenJPAEntityManager) em.getDelegate(); 
    conn = oem.getConnection(); 
    PreparedStatement ps = conn.prepareStatement(myStatement); 
    //initialize parameters in ps 
    ps.executeUpdate(); 
    em.merge(myJpaObject); 
    em.getTransaction().commit(); 
} finally { 
    if (ps != null && !ps.isClosed()) { 
     ps.close(); 
    } 
    if (em.getTransaction().isActive()) { 
    em.getTransaction().rollback(); 
    } 
} 

Merci!

+0

tant qu'ils partagent tous les deux le même objet de connexion (ce que je crois que vous faites en regardant le code), ils peuvent faire partie de la même transaction. Pourquoi ne le vérifie-t-on pas en écrivant un test simple au lieu de poster une question? –

+1

Je vais éditer ma question de manière appropriée - cela semble être entièrement fonctionnel (je l'ai testé avec du code réel, et il semble fonctionner correctement). Je suis nouveau dans les bases de données JPA/JDBC/en général, et je crains qu'il y ait un problème subtil dont je ne suis pas conscient et qui n'apparaisse pas dans mes cas de test simples. – Sbodd

Répondre

3

Avec un tweak, je pense que cela devrait aller.

Il convient de noter what the OpenJPA documentation has to say about it:

La connexion retournée est uniquement garanti transactionnellement compatible avec d'autres opérations EntityManager si le EntityManager est dans une transaction gérée ou non optimiste, si l'EntityManager a vidées dans le courant transaction, ou si vous avez utilisé la méthode OpenJPAEntityManager.beginStore pour vous assurer qu'une transaction datastore est en cours. Fermez toujours la connexion renvoyée avant de tenter toute autre opération EntityManager. OpenJPA s'assurera que la connexion native sous-jacente n'est pas libérée si une transaction de banque de données est en cours.

Votre transaction n'est pas gérée, mais elle est, je pense, non optimiste. De plus, vous n'avez pas effectué de travail JPA entre le démarrage de la transaction et l'exécution des tâches JDBC, donc je pense que vous tombez probablement sous le cas "si l'EntityManager a été vidé dans la transaction en cours".

La seule chose que vous ne faites pas est de fermer la connexion avant de continuer avec JPA. Je suppose qu'OpenJPA ne renvoie pas la connexion réelle qu'il utilise, mais un peu d'encapsulation autour de celui-ci qui devrait être fermé avant qu'OpenJPA reprenne le travail.

+0

Merci; c'est exactement le genre de feedback que je cherchais! – Sbodd

Questions connexes