Finally, 搞清楚了些Hibernate 的对JTA 的支持。
有几个非常重要的property 需要配置
<prop key="hibernate.current_session_context_class">
jta
</prop>
<prop key="hibernate.transaction.manager_lookup_class">
org.hibernate.transaction.WebSphereTransactionManagerLookup
</prop>
<prop key="hibernate.transaction.factory_class">
org.hibernate.transaction.CMTTransactionFactory
扫描二维码关注公众号,回复:
733408 查看本文章
</prop>
1, hibernate.transaction.manager_lookup_class 是用来在SessionFactory 起来的时候调用在 获取 TransactionManager 的, 在 WebSphere 下比较特殊用 这个 WebSphereTransactionManagerLookup。 其它的很多应用服务器比如GlassFish 是通过JNDI 来得到 TransactionManager 的。 GlassFish 下用
org.hibernate.transaction.SunONETransactionManagerLookup
这样Hibernate就可以拿到正确的TransactionManager 了。
2, hibernate.current_session_context_class 是用来配置 SessionContext 的, 它跟SessionFactory 一样可以理解成是个单例。 一个Hibernate configuration 对应一个SessionFactory, 一个SessionFactory 对应一个CurrentSessionContext. 在应用程序中 我们最好是都通过 SessionFactory.getCurrentSession() 来获取Session。它的过程大概是这样的,
2.1 SessionFactory.getCurrentSession() 会调用 JTASessionContext.currentSession();
2.2 JTASessionContext 维护了一个 trasaction 跟 session 的 map。JTASessionContext.currentSession() 的逻辑是先 根据TractionManager 获取当前 tranction , 然后 来这个map 找对应的session 如果没有 就创建一个新的SessionImpl。
2.3 在SessionImpl 建构函数中 会创建一个新的JDBCContext. 这个JDBCContext 名字比较悲催啊其实不管是JDBC 还是JTA 都是需要它的。 以前被它给忽悠了, 其实在JTA的环境下它的作用更大的说。在它的建构函数中 调用了一个 非常重要的方法 registerSynchronizationIfPossible。
public boolean registerSynchronizationIfPossible() {
if ( isTransactionCallbackRegistered ) { // we already have a callback registered; either a local // (org.hibernate.Transaction) transaction has accepted // callback responsibilities, or we have previously // registered a transaction synch. return true; } boolean localCallbacksOnly = owner.getFactory().getSettings() .getTransactionFactory() .areCallbacksLocalToHibernateTransactions(); if ( localCallbacksOnly ) { // the configured transaction-factory says it only supports // local callback mode, so no sense attempting to register a // JTA Synchronization return false; } TransactionManager tm = owner.getFactory().getTransactionManager(); if ( tm == null ) { // if there is no TM configured, we will not be able to access // the javax.transaction.Transaction object in order to // register a synch anyway. return false; } else { try { if ( !isTransactionInProgress() ) { log.trace( "TransactionFactory reported no active transaction; Synchronization not registered" ); return false; } else { javax.transaction.Transaction tx = tm.getTransaction(); if ( JTAHelper.isMarkedForRollback( tx ) ) { // transactions marked for rollback-only cause some TM impls to throw exceptions log.debug( "Transaction is marked for rollback; skipping Synchronization registration" ); return false; } else { if ( hibernateTransaction == null ) { hibernateTransaction = owner.getFactory().getSettings().getTransactionFactory().createTransaction( this, owner ); } tx.registerSynchronization( new CacheSynchronization(owner, this, tx, hibernateTransaction) ); isTransactionCallbackRegistered = true; log.debug("successfully registered Synchronization"); return true; } } } catch( HibernateException e ) { throw e; } catch (Exception e) { throw new TransactionException( "could not register synchronization with JTA TransactionManager", e ); } } }
这个方法 中的 owner.getFactory().getSettings().getTransactionFactory() 就用到了三个配置参数中的最后一个 org.hibernate.transaction.CMTTransactionFactory 。 这个TransactionFactory 的 areCallbacksLocalToHibernateTransactions 返回 false。 如果我们不配置这个参数 owner.getFactory().getSettings().getTransactionFactory() 拿到的就是 JDBCTransactionFactory 了, 它就当然不会走到后面的
tx.registerSynchronization( new CacheSynchronization(owner, this, tx, hibernateTransaction) );
这一行代码 会在JTA transaction 注册一个 Synchronization:CacheSynchronization。
2.4 在CacheSynchronization 实现的 beforeCompletion 方法中 调用 sessionImpl.managedFlush() 方法。
这样我们可以看到 JTA 下面 transaction 跟 session 是 一对一, 在transaction 结束的时候 flush , close session。
当然我们需要我们通过 JTASessionContext.currentSession() 来保证 都是走 JTASessionContext 来管理 session。