web-dev-qa-db-fra.com

Pouvez-vous effectuer plusieurs transactions au sein d’une même session Hibernate?

Pouvez-vous effectuer plusieurs transactions au sein d’une même session Hibernate?

Je ne sais pas s'il s'agit d'un souhait souhaitable. Dans mon code, j'ai un long fil d'exécution et prend des éléments d'une file d'attente bloquante, selon ce qu'il y a dans la file d'attente, il peut être nécessaire de créer et d'enregistrer un objet en veille prolongée ou de ne rien faire. 

Chaque élément est distinct. Par conséquent, si l'élément 1 est enregistré et que l'élément 2 ne parvient pas à enregistrer la raison pour laquelle je ne souhaite pas que cela empêche d'empêcher que l'élément 1 soit ajouté à la base de données. 

Le moyen le plus simple de procéder consiste donc à créer pour chaque élément une nouvelle session, une transaction ouverte, un nouvel objet, une transaction de validation, une session fermée.

Cependant, cela signifie qu'une nouvelle session est créée pour chaque élément, ce qui semble aller à l'encontre des recommandations propres à Hibernates de ne pas utiliser le modèle Session par requête. Donc, mon alternative était de créer une session dans le thread, puis d'ouvrir et de valider une nouvelle transaction si nécessaire pour créer un nouvel objet. Mais je n'ai vu aucun exemple de cette approche et je ne suis pas sûr que cela fonctionne réellement. 

22
Paul Taylor

Le modèle de session par demande utilise une connexion JDBC par session si vous exécutez des transactions locales. Pour JTA, les connexions sont libérées de manière agressive après chaque instruction pour être à nouveau acquises pour l'instruction suivante.

L'API de transaction Hibernate délègue le début/la validation/l'annulation à la connexion JDBC pour les transactions locales et à la UserTransaction associée pour JTA . Par conséquent, vous pouvez exécuter plusieurs transactions sur la même session Hibernate, mais il y a un problème. Une fois qu'une exception est levée, vous ne pouvez plus réutiliser cette session.

Mon conseil est de diviser pour régner. Il suffit de scinder tous les éléments, de construire un objet Command pour chacun d’eux et de les envoyer à un ExecutorService#invokeAll . Utilisez la liste renvoyée pour itérer et appelez Future#get() pour vous assurer que le thread d'origine attend après la fin de tous les travaux par lots. 

La ExecutorService veillera à ce que vous exécutiez toutes les commandes simultanément et chaque commande devrait utiliser un service qui utilise son propre @Transaction. Étant donné que les transactions sont liées à des threads, tous les travaux en mode batch seront exécutés de manière isolée .

22
Vlad Mihalcea

De toute évidence, vous pouvez. Une session d'hibernation est plus ou moins une connexion à une base de données et un cache pour les objets de base de données. Et vous pouvez avoir plusieurs transactions successives dans une seule connexion à la base de données. De plus, lorsque vous utilisez un pool de connexions, la connexion n'est pas fermée, mais recyclée.

Que vous deviez ou non est une question de réutilisation des objets de session. S'il y a de bonnes chances mais que vous puissiez réutiliser des objets qu'une transaction précédente a mis en session, vous devez conserver une seule session pour plusieurs transactions. Mais si un objet a été validé, il ne sera jamais réutilisé, il est certainement préférable de fermer la session et d'en rouvrir un nouveau, ou simplement de l'effacer.

Comment faire :

Si vous avez un objet Session, vous créez des transactions avec:

Transaction transaction;
transaction = session.beginTransaction();
... (operations in the context of transaction)
transaction.commit();
... (other commands outside of any transaction)
transaction = session.beginTransaction();
... (and so on and so forth ...)
11
Serge Ballesta

De la documentation hibernate 

"Une session est un objet peu coûteux et sans threadsafe qui doit être utilisé une fois, puis ignoré pour: une requête unique, une conversation ou une unité de travail. Une session n'obtiendra pas de connexion JDBC, ni de source de données, Il ne consommera aucune ressource avant d’être utilisé. "

donc, si vous créez des sessions encore et encore, le système ne sera pas surchargé. Si vous poursuivez une session trop longtemps, des problèmes peuvent survenir, car la session n’est pas sécurisée pour les threads. À mon avis, la solution la plus simple est la meilleure "La méthode la plus simple consiste à définir pour chaque élément à créer un nouveau session, transaction ouverte, sauvegarde du nouvel objet, transaction de validation, fermeture de la session "

En passant, si vous créez un enregistrement unique de tout ce dont vous n’avez pas besoin trop de transaction. créer un seul enregistrement est par nature une chose "tout ou rien" pour laquelle nous utilisons transaction

3
faisalbhagat
package hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
class Tester {
public static void main(String[] args) {
    SessionFactory sf = new org.hibernate.cfg.Configuration().configure().buildSessionFactory(new StandardServiceRegistryBuilder().configure().build());
    Session session = sf.openSession();
    session.beginTransaction();
        Student student = new Student();
    student.setName("Mohammad Faizan");
    student.setRollNo(1309114040);
        session.save(student);
    session.getTransaction().commit();
    session.getTransaction().begin();
    session.load(Student.class,23);
    student.setName("New Name");
    student.setRollNo(123);
    session.update(student);
    session.getTransaction().commit();
    session.close();
  }
}
0
Faizan Mohammad

La réponse courte est oui, vous pouvez utiliser la même session pour la transaction. Jetez un coup d'oeil à org.hibernate.Transaction.

0
Vinay