Regarding Session reuse: If you work with Spring's HibernateTemplate or SessionFactoryUtils.getSession/closeSessionIfNecessary, you will automatically receive the same Session instance within a transaction, no matter if by HibernateTransactionManager or JtaTransactionManager.
This allows to leverage Hibernate's first-level cache throughout a transaction and is more efficient than using multiple short-lived Session instances. Furthermore, it will automatically guarantee proper JVM-level cache callbacks at transaction completion.
Code that leverages this mechanism could look as follows. Delegating Session lifecycle management to SessionFactoryUtils allows Spring to detect a Session instance that is bound to an existing transaction via the current thread. Alternatively, use Spring's HibernateTemplate which automatically delegates to SessionFactoryUtils underneath.
Code:
//begin tx (with spring tx api)
Session ses = SessionFactoryUtils.getSession(sf);
//do some work
ses.flush();
ses.close();
//open again a session
ses = sf.openSession();
//do some work
ses.flush();
SessionFactoryUtils.closeSessionIfNecessary(session, sf);
//commit tx
Of course, the two data access operations can be in different methods, possibly in different data access objects. Typically, transactions will be demarcated at the business facade level, calling various DAO methods within. All of these calls will reuse the same Session instance within a transaction, without any additional effort by the application developer.
I agree that JTA's UserTransaction API is pretty simple, but Spring's PlatformTransactionManager isn't really harder: 3 methods there too - you just need to pass the TransactionStatus returned by getTransaction to commit/rollback. Spring also offers TransactionTemplate, allowing to implement a callback that automatically gets executed transactionally, and of course declarative transactions via AOP.
The difference is that PlatformTransactionManager uses a well-defined unchecked exception hierarchy, while UserTransaction throws various
unrelated checked JTA exceptions. Take for example UserTransaction.commit: 4 unrelated checked exceptions plus 2 unchecked ones. That's why UserTransaction callers often resort to "catch(Exception)", rethrowing them as some ad-hoc RuntimeException.
Juergen