2011-10-19 3 views
1

J'ai une méthode de base que j'écris afin de ne pas répéter la même logique de transaction/session d'hibernation encore et encore. C'est assez simple, mais il y a un problème spécifique que je ne suis pas sûr que l'on puisse résoudre avec cette approche. Imaginez que vous ayez une entité Utilisateur et une entité Autorisation. Si une requête est faite pour enregistrer un utilisateur avec ses permissions correspondantes, alors je pense qu'il serait logique d'effectuer les deux opérations dans une seule transaction, car ne pouvoir sauvegarder qu'une seule de ces entités pourrait être considéré comme une corruption de données. Par exemple, si vous ne sauvegardez pas les autorisations de l'utilisateur, cela justifie une annulation des données utilisateur précédemment insérées. J'ai fait la méthode suivante pour autoriser les opérations de mise en veille prolongée générique qui pourraient fonctionner avec la transaction courante si c'était nécessaire, bien que je pense maintenant que dans sa forme actuelle cela ne fonctionnera pas depuis l'appel de session.beginTransaction(); retournera probablement une nouvelle transaction même si la précédente n'a pas été validée (est-ce le cas?). Supposons que je l'ai modifié pour qu'il renvoie la session et la transaction en cours s'il était spécifié qu'il y aurait plus d'opérations pour la transaction en cours, pensez-vous que cela fonctionnerait? Serait-il souhaitable de faire quelque chose comme ça, ou recommanderiez-vous un changement d'approche? MerciModèle Hibernate pour la réutilisation des transactions

protected <T> void baseOperation(Class<T> entityClass, List<T> instances, BaseHibernateDAO.Operations operation, boolean isLastOperation) throws Exception 
{ 
    Session session = null; 
    Transaction transaction = null; 
    boolean caughtException = false; 

    //get session from factory 
    session = HibernateSessionFactory.getSession(); 

    try 
    { 
     //get current transaction 
     transaction = session.beginTransaction(); 

     for (Object instance : instances) //perform operation on all instances 
     { 
      log.debug(String.format("Will perform %s operation on %s instance.", operation.name(), entityClass.getName())); 

      switch (operation) //perform requested operation 
      { 
       case SAVE: 
        session.save(instance); 
        break; 
       case UPDATE: 
        session.update(instance); 
        break; 
       case SAVEORUPDATE: 
        session.saveOrUpdate(instance); 
        break; 
       case DELETE: 
        session.saveOrUpdate(instance); 
        break; 
      } 

      log.debug(String.format("%s operation on %s instance was succesful.", operation.name(), entityClass.getName())); 
     } 

     session.flush(); //synchronize 

     if (isLastOperation) //if this is the last operation of the transaction 
     { 
      transaction.commit(); 
      log.debug("Transaction commited succesfully."); 
     } 
    } 
    catch (Exception e) //error occurred 
    { 
     caughtException = true; 

     //roll-back if transaction exists 
     if (transaction != null) 
     { 
      transaction.rollback(); 
     } 

     //log and re-throw 
     log.error("An error occurred during transaction operation.", e); 
     throw e; 
    } 
    finally //cleanup tasks 
    { 
     if (isLastOperation || caughtException) //close session if there are no more pending operations or if an error occurred 
     { 
      HibernateSessionFactory.closeSession(); 
     } 
    } 
} 

Répondre

7

« Recommandable » serait d'arrêter d'essayer de réécrire le code qui a déjà été écrit, débogué, traînés dans la boue, plus débogué, et déployé des milliers de fois. Par exemple, les problèmes et les considérations que vous rencontrez ont déjà été rencontrés et surmontés, et les solutions sont prouvées. En outre, après avoir été largement utilisé et amélioré, ils nécessitent beaucoup moins d'efforts à utiliser que ce que vous mettez dans votre solution personnalisée. Découvrez Spring's Hibernate support, en particulier "Implementing DAOs based on plain Hibernate 3 API" et "Declarative transaction demarcation". Pour en savoir plus, il y a un chapter on transaction management entier.

J'ai un sample project on github où vous pouvez voir un exemple très simple d'utilisation de Spring pour gérer les sessions et transactions Hibernate dans le contexte d'une application web (en utilisant Spring MVC).

Mise à jour: Pour ceux qui viennent le long plus tard, ils ne doivent pas fouiller dans les commentaires:

Il existe trois façons générales d'utiliser le traitement des transactions de printemps: déclarative defining which methods are transactional with XML, déclarative annotating methods as @Transactional, ou par programmation using TransactionTemplate.

+1

Bon point. N'oubliez pas non plus les autres options basées sur les standards d'EJB3 et Seam 3 (basées sur JSR-299). –

+0

Ce n'est pas que j'essaie volontiers de le réécrire, je ne savais pas qu'il existait. Le problème est que je n'ai actuellement pas le temps d'apprendre un autre cadre. J'ai regardé votre exemple et cela semblait assez simple, mais je sais que ce ne sera pas le cas une fois que j'essayerai de l'appliquer à des objets plus complexes. Je n'ai pas encore trouvé un seul exemple qui exécute deux opérations dans une seule transaction, au printemps ou autrement (le plus que j'ai trouvé sont trois points ... impliquant qu'il y aurait plus de code) .Si je ne peux pas vois-le je ne peux pas le comprendre, et donc je préfère le faire moi même si ce n'est pas vrai et vrai – JayPea

+0

Mais de toute façon, merci de me pointer dans cette direction, j'essaierai d'apprendre le printemps quand j'aurai le temps, mais pour l'instant c'est trop risqué d'apprendre quelque chose comme ça au moment du développement :) – JayPea

Questions connexes