JTA
Switch to use JTA, instead of native JDBC transactions. All new application servers support JTA natively. With JTA, the session is bound to the transaction. If you call sessionFactory.getCurrentSession(), anytime between userTransaction.begin() and userTransaction.commit(), a session bound to this transaction is returned. User transaction is usually obtained via JNDI. So, an example of code:
UserTransaction tx = (UserTransaction)new InitialContext() .lookup("java:comp/UserTransaction"); SessionFactory factory = HibernateUtil.getSessionFactory(); PersonDao dao = new PersonDao(factory); try{ tx.begin(); dao.saveOrUpdate(person); tx.commit(); } catch( Exception ex) { tx.rollback(); }while the only thing that the Dao needs to do is to request the session via: factory.getCurrentSession().
The required Hibernate configuration file hibernate.cfg.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory name="hibernate/sessionFactory"> <property name="transaction.manager_lookup_class">org.hibernate.transaction.SunONETransactionManagerLookup</property> <property name="transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property> <property name="connection.datasource">jdbc/xaderby</property> <property name="dialect">org.hibernate.dialect.DerbyDialect</property> <property name="current_session_context_class">jta</property> <property name="hbm2ddl.auto">create</property> <mapping resource="olcc/entity/Person.hbm.xml"/> </session-factory> </hibernate-configuration>where jdbc/xaderby is a data source defined on Glassfish, of type javax.sql.XADataSource.
Configuration
Glassfish 3
Hibernate 3.5
JDK 6 (Derby included)
Result
This configuration results in the following error message:
FINEST: saving transient instance FINE: surrounding JTA transaction suspended [JavaEETransactionImpl: txId=1 nonXAResource=null jtsTx=null localTxStatus=0 syncs=[org.hibernate.transaction.CacheSynchronization, org.hibernate.context.JTASessionContext$CleanupSynch@1d069e4]] FINE: opening JDBC connection INFO: JTS5014: Recoverable JTS instance, serverId = [100] FINE: select next_hi from hibernate_unique_key for read only with rs FINE: update hibernate_unique_key set next_hi = ? where next_hi = ? FINE: closing JDBC connection (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0) SEVERE: org.hibernate.HibernateException: unable to resume previously suspended transaction at org.hibernate.engine.transaction.Isolater$JtaDelegate.delegateWork(Isolater.java:179) at org.hibernate.engine.transaction.Isolater.doIsolatedWork(Isolater.java:64) at org.hibernate.engine.TransactionHelper.doWorkInNewTransaction(TransactionHelper.java:74) at org.hibernate.id.TableGenerator.generate(TableGenerator.java:118) at org.hibernate.id.TableHiLoGenerator.generate(TableHiLoGenerator.java:84) at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:122)When I tried using a plain javax.sql.DataSource instead of XADataSource, I was getting XAResource.start error.
Remaining Questions:
- findAllByProperty(), findByCriteria() and/or findByExample() methods. Commonly used. What is the right way to implement them?
No comments:
Post a Comment