Reputation: 1828
I have been struggling for more than 2 days, in order to setup JTA with a stand alone Java application, but unfortunately id didn't work, I would appreciate some help.
General Information:
Spring configuration file:
<bean class="com.arjuna.ats.jta.TransactionManager" factory-method="transactionManager" id="arjunaTransactionManager" />
<bean class="com.arjuna.ats.jta.UserTransaction" factory-method="userTransaction" id="arjunaUserTransaction" />
<bean class="org.springframework.transaction.jta.JtaTransactionManager" id="transactionManager">
<property name="transactionManager">
<ref bean="arjunaTransactionManager" />
</property>
<property name="userTransaction">
<ref bean="arjunaUserTransaction" />
</property>
</bean>
<tx:annotation-driven />
Hibernate Configuration File:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
<property name="connection.url">jdbc:sqlserver://localhost:1433;databaseName=TestDB</property>
<property name="connection.username">user</property>
<property name="connection.password">password</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.SQLServerDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">jta</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<property name="transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property>
<property name="transaction.jta.platform">org.hibernate.service.jta.platform.internal.JBossStandAloneJtaPlatform</property>
</session-factory>
</hibernate-configuration>
At this point I need to create the hibernate session factory, and I want to create it programmatically, to do so I used the following code snippet, where I create a spring LocalSessionFactoryBean pass to it the hibernate configuration resource and retrieve the SessionFactory from it using the .getObject() method.
This code works correctly and creates a SessionFactory object, this object is used in the next code snippet.
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
JtaTransactionManager trxManager = applicationContext.getBean(JtaTransactionManager.class);
sessionFactoryBean.setJtaTransactionManager(trxManager);
sessionFactoryBean.setConfigLocation(resource);
sessionFactoryBean.afterPropertiesSet();
SessionFactory sessionFactory = sessionFactoryBean.getObject();
After that I have a Service class that does an insert into a TABLE:
package com.core.service;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
@Scope("prototype")
public class TestService {
@Transactional
public void testTrx() throws Exception {
SessionFactory sessionFactory = // retrieve session factory created before
Session session = sessionFactory.getCurrentSession();
Query query = session.createSQLQuery("insert into TABLE1 (col1, col2) values (:v1, :v2)");
query.setParameter("v1", "value1");
query.setParameter("v2", "value2");
query.executeUpdate();
}
}
And finally a JUnit test that loads the Spring context and initializes everything, and then executes the following lines:
@Test
public void testTransactionRollback() throws Exception {
TestService testService = applicationContext.getBean(TestService.class);
testService.testTrx();
}
The Problem: When I execute the JUnit test I get a green bar and I see that there is an SQL statement that inserts into the table, and I see that a transaction is opened and committed, however if I go to the database I don't see the inserted rows.
My Conclusion: I tried to set the hibernate configuration connection.autocommit=true and the row is created in the database correctly, so I assume that Yes JTA transactions are opened and closed but the Hibernate Session Factory is not using them, instead it is using its own. Am I missing some configuration?
15:14:20.423 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'testService'
15:14:20.425 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'transactionManager'
15:14:20.432 [main] DEBUG o.s.t.jta.JtaTransactionManager - Creating new transaction with name [com.core.service.TestService.testTrx]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
15:14:20.448 [main] INFO com.arjuna.ats.arjuna - ARJUNA012163: Starting service com.arjuna.ats.arjuna.recovery.ActionStatusService on port 36097
15:14:20.453 [main] INFO com.arjuna.ats.arjuna - ARJUNA012337: TransactionStatusManagerItem host: 127.0.0.1 port: 36097
15:14:20.460 [main] INFO com.arjuna.ats.arjuna - ARJUNA012170: TransactionStatusManager started on port 36097 and host 127.0.0.1 with service com.arjuna.ats.arjuna.recovery.ActionStatusService
15:14:20.488 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'sessionFactoryManagerImpl'
15:14:20.524 [main] DEBUG o.h.e.j.i.LogicalConnectionImpl - Connection provider reports to not support aggressive release; overriding
15:14:20.533 [main] DEBUG o.h.e.t.i.TransactionCoordinatorImpl - successfully registered Synchronization
15:14:20.565 [main] DEBUG org.hibernate.SQL - insert into TABLE1 (col1, col2) values (?, ?)
Hibernate: insert into TABLE1 (col1, col2) values (?, ?)
15:14:20.566 [main] DEBUG o.h.e.j.i.LogicalConnectionImpl - Obtaining JDBC connection
15:14:20.566 [main] DEBUG o.h.e.j.i.LogicalConnectionImpl - Obtained JDBC connection
15:14:20.575 [main] DEBUG o.h.e.q.spi.NativeSQLQueryPlan - bindNamedParameters() value1 -> v1 [1]
15:14:20.582 [main] DEBUG o.h.e.q.spi.NativeSQLQueryPlan - bindNamedParameters() value2 -> v2 [2]
15:14:20.589 [main] DEBUG o.s.t.jta.JtaTransactionManager - Initiating transaction commit
15:14:20.590 [main] DEBUG o.h.e.j.i.LogicalConnectionImpl - Aggressively releasing JDBC connection
15:14:20.590 [main] DEBUG o.h.e.j.i.LogicalConnectionImpl - Releasing JDBC connection
15:14:20.590 [main] DEBUG o.h.e.j.i.LogicalConnectionImpl - Released JDBC connection
15:14:20.595 [Listener:36097] DEBUG com.arjuna.ats.arjuna - Recovery listener existing com.arjuna.ats.arjuna.recovery.ActionStatusService
Upvotes: 2
Views: 3505
Reputation: 240
I think it is because Your database connection is not bound with JTA. You have only synchronized hibernate with JTA. You should use com.arjuna.ats.jdbc.TransactionalDriver in order to create conenction:
TransactionalDriver arjunaJDBC2Driver = new TransactionalDriver();
Connection connection = arjunaJDBC2Driver.connect(url, dbProps);
spring example:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>com.arjuna.ats.jdbc.TransactionalDriver</value>
</property>
<property name="url" value="jdbc:arjuna:mysql://host:3306/dbName"/>
<property name="connectionProperties">
<ref bean="dsProps"/>
</property>
</bean>
Hope this help
Upvotes: 1