In JEE, JTA allows transactions to be distributed across multiple resources. You don't need a JEE server though to run JTA transactions, Tomcat will do (possibly with a bit more hassle).
I decided to use JBoss 6 because it is a popular JEE server - but I would assume you can successfully run the code on any server as long as the data source is set correctly (plus with minor tweaks of server dependent stuff).
(I also wrote a post on non-jta transactions with Spring 3, JBoss 6 and Hibernate 3.)
applicationContext.xml
This is our Spring config file.
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="Dogs" /> </bean> <bean id="dogsDao" class="me.m1key.springtx.dao.DogsDaoImpl" /> <bean id="dogsBean" class="me.m1key.springtx.beans.DogsBean" scope="singleton"> <property name="dogsDao" ref="dogsDao" /> </bean> <tx:annotation-driven transaction-manager="myTransactionManager" /> <tx:jta-transaction-manager /> <bean id="myTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" /> <bean class=" org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor " />Look closely, notice the jta-transaction-manager annotation and JtaTransactionManager.
persistence.xml
This is our persistence.xml. It's a bit different from the non-jta version.
… <persistence-unit name="Dogs" transaction-type="JTA"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>java:/DogsDS</jta-data-source> <class>me.m1key.springtx.entities.Dog</class> <properties> <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup" /> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.format_sql" value="true" /> <property name="hibernate.hbm2ddl.auto" value="create" /> </properties> </persistence-unit> …Notice the transaction-type attribute. It's JTA as opposed to RESOURCE_LOCAL in the case of non-JTA. You must also specify transaction manager lookup class which is server dependent.
DAO
@PersistenceContext private EntityManager em; @SuppressWarnings("unchecked") @Transactional(readOnly = true) public List<Dog> retrieveAllDogs() { return em.createQuery("from Dog").getResultList(); }
That's it! To run this example you need a database server running. I'm using HSQLDB. You can download source code and there is a batch file there that runs this HSQLDB server. The application is to be deployed on JBoss 6.
You call the transactional operation by accessing http://localhost:8080/springtx-jta-0.0.1-SNAPSHOT/myurl.
pom.xml
For reference, the relevant parts of the POM file.
<dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>3.6.0.Final</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-commons-annotations</artifactId> <version>3.2.0.Final</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.hibernate.javax.persistence</groupId> <artifactId>hibernate-jpa-2.0-api</artifactId> <version>1.0.0.Final</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>3.6.0.Final</version> <type>jar</type> <scope>provided</scope> </dependency> <dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>1.8.0.7</version> <type>jar</type> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>3.0.3.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>3.0.3.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>3.0.3.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.5.8</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.5.8</version> </dependency> <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>3.1</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>3.0.3.RELEASE</version> <type>jar</type> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.8.1</version> <type>jar</type> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.0.3.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>3.0.3.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.jboss.spec.javax.servlet</groupId> <artifactId>jboss-servlet-api_3.0_spec</artifactId> <version>1.0.0.Final</version> <scope>provided</scope> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.2</version> </dependency> </dependencies> <repositories> <repository> <id>r.j.o-groups-public</id> <url>https://repository.jboss.org/nexus/content/groups/public/</url> </repository> </repositories>