Archive for ottobre 10, 2006

Transazioni Hibernate con JTA

Fino ad oggi ho sempre gestito le transazioni con Hibernate tramite il bind della sessione al corrente thread java. Questa soluzione, in un’ambiente di EJB multi-tier, risulta inefficiente nel momento in cui la transazione richiede 2 o più chiamate all’ejb che funge da DAO.

Figura1

Come si evince dalla figura, dopo la chiamata (1), l’ejb di DaoManager mi restituisce un oggetto hibernate idradato ma, gestendo lui le sessioni, questa risulta ormai chiusa e anche operazioni di logica banali che io faccio su questo oggetto potrebbero scatenarmi un’eccezione (si pensi ad un’oggetto con una lista lazy non inizializzata, anche un semplice set su un campo non lazy può scatenare una LazyInitizalizationException).

La soluzione a questo problema potrebbe essere quella di aprire la sessione hibernate a livello dell’ejb di Business Logic. Effettivamente funziona, ma passare la sessione ad ogni chiamata all’ejb di DaoManager è poco pratico e soprattutto mi vincolerebbe a farlo anche nel caso in cui una semplice transazione si traduce in una chiamata 1:1 tra ejb di logica e DAO.

Per chi utilizza una versione di Hibernate precedente alla 3.0.1, questa rimane la soluzione migliore, indipendentemente dall’application server su cui gira. Dalla versione 3.0.1, Hibernate, è invece in grado di lavorare in un ambiente che supporta JTA, gestendo automaticamente il bind della sessione hibernate alla corrente transazione JTA. Lavorando con JBoss 4.0.4.GA ho provato e testato con successo questa implementazione.

Ho modificato la HibernateUtil class nel mio framework, riducendola al nocciolo della semplice lookup della SessionFactory:

static {
   try {
       Context ctx = new InitialContext();
       sessionFactory = (SessionFactory)ctx.lookup("java:/hibernate/MySessionFactory");
   } catch (Throwable ex) {
       logWriter.error("Inizializzazione SessionFactory fallita." + ex);
       initializationException =
           new FrameworkException("Inizializzazione SessionFactory fallita.", ex);
   }
}

public static SessionFactory getSessionFactory() throws FrameworkException {
   if (initializationException != null){
       throw initializationException;
   }
   return sessionFactory;
}

Ho modificato il file di configurazione hibernate-service.xml per il servizio har:

<server>
   <mbean code="org.hibernate.jmx.HibernateService" name="jboss.har:service=Hibernate-GTS">
       <attribute name="Datasource">java:/MyDatasource</attribute>
       <attribute name="Dialect">org.hibernate.dialect.Oracle9Dialect</attribute>
       <attribute name="JndiName">java:/hibernate/MySessionFactory</attribute>
       <attribute name="CacheProviderClass">
           org.hibernate.cache.HashtableCacheProvider</attribute>
       <attribute name="ShowSqlEnabled">false</attribute>
       <attribute name="TransactionStrategy">
           org.hibernate.transaction.JTATransactionFactory</attribute>
       <attribute name="TransactionManagerLookupStrategy">
           org.hibernate.transaction.JBossTransactionManagerLookup</attribute>

       <attribute name="MapResources">
           example/MyPOJO1.hbm.xml,
           example/MyPOJO2.hbm.xml
       </attribute>
   </mbean>
</server>

…e infine ho piazzato nel DaoManager un metodo privato di utilità per il reperimento della sessione di Hibernate, che utilizzerò in ogni metodo:

private Session getCurrentSession() throws DaoManagerException {
   try {
       return HibernateUtil.getSessionFactory().getCurrentSession();
   } catch (FrameworkException ex) {
       logWriter.error("---- Errore nel recuperare la SessionFactory", ex);
       throw new DaoManagerException("Errore nel recuperare la SessionFactory", ex);
   } catch (HibernateException ex){
       logWriter.error("---- Errore nel recuperare la Sessione hibernate", ex);
       throw new DaoManagerException("Errore nel recuperare la Sessione hibernate", ex);
   }
}

In questo modo nell’ejb di BusinessLogic posso implementare tutta la logica che voglio tra le varie chiamate al DaoManager senza preoccuparmi della sessione di Hibernate:

try {

   MyPOJO1 p1 = localDaoManager.getPOJO1ById(id);

   // do something

   localDaoManager.doSomething(....);

} catch (DaoManagerException ex){
   sessionContext.setRollbackOnly();
}

Il vantaggio di tutto questo è che la sessione di Hibernate è legata alla transazione JTA (come trasaction attribute ho impostato RequiresNew per l’ejb di BusinessLogic e Mandatory per l’ejb di DAOManager). La sessione viene automaticamente aperta quando getCurrentSession() è invocato per la prima volta e viene automaticamente chiusa quando la termina la transazione.

ottobre 10, 2006 at 2:43 PM 7 commenti


Calendario

ottobre: 2006
L M M G V S D
 1
2345678
9101112131415
16171819202122
23242526272829
3031  

Posts by Month

Posts by Category