Reputation: 8323
We have a spring application deployed on a jboss 7 server.
The application uses multiple datasources obtained from jboss through jndi.
The Transaction management is also provided by the Java EE container (we use Spring JtaTransactionManager)
The app architecture is a legacy one with DAOs extending hibernate Templates (using Spring HibernateDaoSupport).
Transaction are managed in the service layer using @Transactional
annotations.
My 1st questions are:
when encountering the annotation, how does the transaction manager know which datasources will be involved in the transaction ?
when does it effectively retrieve a JDBC connection and on which datasources ? when does it effectively open a transaction ? (only DAOs got a reference to the sessionFactory bound to a specific datasource).
The driver we are using does not support distributed (XA) transactions, in most case we doesn't need multi-phase commit as only one datasource is written. Anyway when we access (read only) other datasources within the same transaction we got messages in logs :
INFO [org.jboss.jca.core.api.connectionmanager.ccm.CachedConnectionManager] (http--0.0.0.0-8080-4) IJ000100: Closing a connection for you. Please close them yourself: org.jboss.jca.adapters.jdbc.jdk6.WrappedConnectionJDK6@691644c: java.lang.Throwable: STACKTRACE
at org.jboss.jca.core.connectionmanager.ccm.CachedConnectionManagerImpl.registerConnection(CachedConnectionManagerImpl.java:265)
at org.jboss.jca.core.connectionmanager.AbstractConnectionManager.allocateConnection(AbstractConnectionManager.java:495)
at org.jboss.jca.adapters.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:129)
at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection(LocalDataSourceConnectionProvider.java:81) [spring-orm-3.0.5.RELEASE.jar:3.0.5.RELEASE]
at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:446) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
[...]
Is there a way to properly manage connection release in such a case without using XA datasources ?
Otherwise can those message safely be ignored or do they denote a real problem ? (log level is INFO)
[edit]
Some additional data on configuration :
exemple of datasource declaration
<!-- JNDI datasource -->
<bean id="customersDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/${shared.datasource}" />
</bean>
Associated sessionFactory
<bean id="sharedSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="customersDataSource" />
<property name="configLocation" value="classpath:hibernate.shared.cfg.xml" />
<property name="hibernateProperties">
<props>
<!-- jboss specific transaction management -->
<prop key="transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</prop>
<prop key="transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</prop>
<prop key="hibernate.connection.release_mode">after_transaction</prop>
<prop key="hibernate.transaction.auto_close_session">true</prop>
[...]
</props>
</property>
</bean>
We are thinking about playing with hibernate.connection.release_mode
but even if only one datasource is actually written within a single transaction, it's not always the same one.
Upvotes: 5
Views: 2490
Reputation: 8323
Well I was making a mountain out of a mole hill.
In fact some access to datasource are outside of a transactional scope, as the hibernate connection release mode is set to after_transaction
connection is never released.
I just added some missing @Transactional annotations and it fixed the problem.
Note: it seems that a propagation set to support
trigger the connection release even when the caller is not inside a transactional scope
Upvotes: 0
Reputation: 153810
When encountering the annotation, how does the transaction manager know which datasources will be involved in the transaction ?
As long as you have:
<tx:annotation-driven/>
Spring should use a TransactionInterceptor that intercepts your service method call and wraps the request in a JTA transaction.
Spring doesn't have an actual XA transaction manager, the JtaTransactionManager is only a facade requiring a backend JTA provider (like JBoss AS transaction manager).
You still need to configure the Jboss TM, like this:
<bean id="jbossTransactionManager" class="com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple">
</bean>
When does it effectively retrieve a JDBC connection and on which datasources ? when does it effectively open a transaction ? (only DAOs got a reference to the sessionFactory bound to a specific datasource).
The transaction is triggered by the JtaTransactionManager which delegates the actual transaction init request to JBoss TM.
All data sources must be XA complaint, you can't mix JTA with resource-local DataSources. Some transaction manager may use the LastResourceCommit
optimization allowing you to enlist up to one non-XA DataSource.
The data source is enlisted in the current transaction the moment a database connection is wanted:
DataSource.getConnection()
From this point on this connection will participate in the current transaction, hence it will be committed or rollback based on the transaction outcome.
I don't think you should use LocalDataSourceConnectionProvider
. You need to set:
<jta-data-source>java:/WareHouseDS</jta-data-source>
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup" />
Hibernate needs to know where to get the JBoss AS JNDI for the registered DataSource.
Upvotes: 2
Reputation: 178
I think the best way to understand how Jta Transaction Manager works and how it handles multiple datasources is to refer to [Java Transaction API (JTA) specification][1]
.
After downloading it, take a look at 3.3 Transaction interface
and 3.4 XA Ressource interface
sections.
Upvotes: 0