Configure JTA (JOTM) to share hibernate and jdbc connection?
Dear all,
Is it possible use JTA(JOTM) to let HibernateTemplate and JdbcTemplate share the same database connection ? I have tried to configure JtaTransactionManager with HibernateIntercetor, but it does not work... below is my test configuration:
applicationContext.xml
Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="jotm"
class="org.springframework.transaction.jta.JotmFactoryBean" />
<bean id="innerDataSource"
class="org.enhydra.jdbc.standard.StandardXADataSource"
destroy-method="shutdown">
<property name="transactionManager">
<ref local="jotm" />
</property>
<property name="driverName">
<value>oracle.jdbc.driver.OracleDriver</value>
</property>
<property name="url">
<value>
jdbc:oracle:thin:@abcd.bioinfo:1521:ABCD
</value>
</property>
</bean>
<bean id="dataSource"
class="org.enhydra.jdbc.pool.StandardXAPoolDataSource"
destroy-method="shutdown">
<property name="dataSource">
<ref local="innerDataSource" />
</property>
<property name="user">
<value>abcd</value>
</property>
<property name="password">
<value>abcd</value>
</property>
<property name="maxSize">
<value>30</value>
</property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="mappingDirectoryLocations">
<list>
<value>classpath:/antar/</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.dialect">
org.hibernate.dialect.Oracle9Dialect
</prop>
</props>
</property>
<property name="jtaTransactionManager">
<ref bean="jotm" />
</property>
</bean>
<bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>
<bean id="hibernateTemplate"
class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="userTransaction">
<ref local="jotm" />
</property>
</bean>
<bean id="checkSameConnection"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref local="transactionManager" />
</property>
<property name="target">
<bean class="antar.config.CheckSameConnectionImpl">
<property name="hibernateTemplate">
<ref bean="hibernateTemplate" />
</property>
<property name="jdbcTemplate">
<ref bean="jdbcTemplate" />
</property>
</bean>
</property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
<property name="postInterceptors">
<list>
<bean
class="org.springframework.orm.hibernate3.HibernateInterceptor">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
</list>
</property>
</bean>
</beans>
CheckSameConnection and CheckSameConnectionImpl are simple
classes and wrapped by transaction. CheckSameConnectionImpl inject HibernateTemplate and JdbcTemplate to check whether the connection is shared.
Code:
public interface CheckSameConnection {
public void doTransaction();
}
public class CheckSameConnectionImpl implements CheckSameConnection {
private HibernateTemplate hibernateTemplate;
private JdbcTemplate jdbcTemplate;
public void doTransaction() {
final XAPoolNativeJdbcExtractor extractor = new XAPoolNativeJdbcExtractor() ;
System.out.println("begin... ");
hibernateTemplate.execute(new HibernateCallback() {
public Object doInHibernate(final Session session)
throws HibernateException, SQLException {
final Connection connFromHibernate = session.connection() ;
jdbcTemplate.execute(new ConnectionCallback() {
public Object doInConnection(final Connection connFromJdbc)
throws SQLException, DataAccessException {
Connection ch = extractor.getNativeConnection(connFromHibernate) ;
Connection cj = extractor.getNativeConnection(connFromJdbc) ;
if( cj== ch) {
System.out.println("same connection");
} else {
System.err.println("not same connection:" + cj +" != " + ch);
}
return null;
}
});
return null;
}
});
System.out.println("done...");
}
}
finally, a simple test case to invoke a transaction wrapped checkSameConnection bean:
Code:
public class HibernateJDBCConnectionTest extends
AbstractDependencyInjectionSpringContextTests {
protected String[] getConfigLocations() {
return new String[] {"/applicationContext-jta.xml"} ;
}
public void testSameConnectionWithSameTransactionManager() {
CheckSameConnection csc = (CheckSameConnection) applicationContext
.getBean("checkSameConnection");
csc.doTransaction();
}
}
and the debug output is
Code:
DEBUG AbstractPlatformTransactionManager - Using transaction object [org.springframework.transaction.jta.JtaTransactionObject@2b3483]
DEBUG AbstractPlatformTransactionManager - Creating new transaction
DEBUG JtaTransactionManager - Beginning JTA transaction
DEBUG TransactionSynchronizationManager - Initializing transaction synchronization
DEBUG SessionFactoryUtils - Opening Hibernate session
DEBUG SessionFactoryUtils - Registering Spring transaction synchronization for new Hibernate session
DEBUG TransactionSynchronizationManager - Bound value [org.springframework.orm.hibernate3.SessionHolder@46c21b] for key [org.hibernate.impl.SessionFactoryImpl@c701cb] to thread [main]
DEBUG HibernateInterceptor - Found thread-bound session for Hibernate interceptor
begin...
DEBUG TransactionSynchronizationManager - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@46c21b] for key [org.hibernate.impl.SessionFactoryImpl@c701cb] bound to thread [main]
DEBUG TransactionSynchronizationManager - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@46c21b] for key [org.hibernate.impl.SessionFactoryImpl@c701cb] bound to thread [main]
DEBUG TransactionSynchronizationManager - Bound value [org.springframework.jdbc.datasource.ConnectionHolder@59e40] for key [StandardXAPoolDataSource: ... **cut**
not same connection:oracle.jdbc.driver.T4CConnection@74641 != oracle.jdbc.driver.T4CConnection@d59861
DEBUG TransactionSynchronizationManager - Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@59e40] for key [StandardXAPoolDataSource: ... **cut**
DEBUG TransactionSynchronizationManager - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@46c21b] for key [org.hibernate.impl.SessionFactoryImpl@c701cb] bound to thread [main]
done...
DEBUG HibernateInterceptor - Not closing pre-bound Hibernate session after interceptor
DEBUG AbstractPlatformTransactionManager - Triggering beforeCommit synchronization
DEBUG AbstractPlatformTransactionManager - Triggering beforeCompletion synchronization
DEBUG TransactionSynchronizationManager - Removed value [org.springframework.orm.hibernate3.SessionHolder@46c21b] for key [org.hibernate.impl.SessionFactoryImpl@c701cb] from thread [main]
DEBUG SessionFactoryUtils - Closing Hibernate session
DEBUG TransactionSynchronizationManager - Removed value [org.springframework.jdbc.datasource.ConnectionHolder@59e40] for key [StandardXAPoolDataSource: ... **cut**
DEBUG AbstractPlatformTransactionManager - Initiating transaction commit
DEBUG JtaTransactionManager - Committing JTA transaction
DEBUG AbstractPlatformTransactionManager - Triggering afterCompletion synchronization
DEBUG TransactionSynchronizationManager - Clearing transaction synchronization
the result shows that TransactionManager and HibernateInterceptor work correctly, however, the connection used by HibernateTemplate is not the same as the one used by JdbcTemplate...
Do I missing something ?
ps. Spring - 1.2rc1
Hibernate - 3.0rc1