Configuring a JBoss + Spring + JPA (Hibernate) + JTA web application

Updated version available: If you are looking for how JPA can be used in JBoss 5 and Spring 3.x versions, look at "Spring JPA web applications (JTA transactions, JBoss 5)". What you find below is a workaround to use JTA transactions in JBoss 4.x versions.

Here's how one might go about deploying a Spring application in JBoss (4.something) that uses JPA with Hibernate as the provider for persistence and JTA for transaction demarcation.

1. Define the Spring configuration file in the web.xml file

        <description>Spring configuration file</description>

2. Define the Spring loader in the web.xml file

        <description>Spring Loader</description>

3. Define the persistence unit reference in the web.xml file (which in fact has no effect until the Servlet container supports Servlet spec 2.5):

            Persistence unit for the bank application.

* Note that this is what enables "<jee:jndi-lookup>" which has been commented out in the below given Spring configuration file.

* For the above to work well, your web.xml should start like this (note the version 2.5):

<web-app version="2.5" xmlns="" xmlns:xsi="" xsi:schemaLocation="">

4. Here's the persistence.xml file. Make the changes to the <jta-data-source> as you have defined in your system (for example in a file like JBOSS_HOME/server/default/deploy/bank-ds.xml - See JBOSS_HOME/docs/examples/jca/ for templates).

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="" xmlns:xsi="" xsi:schemaLocation="">
  <persistence-unit name="BankAppPU" transaction-type="JTA">
      <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
      <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
      <property name="" value="java:/BankAppPU"/>
      <property name="" value="update"/>

5. Here's a sample Spring configuration file (applicationContext.xml):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns=""

    <!-- In a fully J5EE compatible environment, the following xml tag should work in accessing the EMF -->          
    <jee:jndi-lookup id="entityManagerFactory" jndi-name="java:/BankAppPU"/>
    <!-- Hack for JBoss 4.something until full compliance is reached -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
      <property name="persistenceUnitName" value="BankAppPU"/>

    <!-- Let's access the JTA transaction manager of the application server -->
    <bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">
        <property name="transactionManagerName" value="java:/TransactionManager"/>
        <property name="userTransactionName" value="UserTransaction"/>
    <!-- Let's define a DAO that uses the EMF -->
    <bean id="accountHolderDAO" class="bankapp.dao.AccountHolderDAO">
        <property name="emf" ref="entityManagerFactory"/>
    <!-- This is a service object that we want to make transactional.
         You will have an interface implemented (AccountManager) in the class.
    <bean id="accountManager" class="bankapp.AccountManagerImpl">
        <property name="accountHolderDAO" ref="accountHolderDAO"/>
    <!-- The transactional advice (i.e. what 'happens'; see the <aop:advisor/> bean below) -->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <!-- the transactional semantics... -->
            <!-- all methods starting with 'get' are read-only transactions -->
            <tx:method name="get*" read-only="true"/>
            <!-- other methods use the default transaction settings (see below) -->
            <tx:method name="*" read-only="false" />
    <!-- ensure that the above transactional advice runs for execution
      of any operation defined by the AccountManager interface -->
        <aop:pointcut id="accountManagerOperation",
           expression="execution(* bankapp.AccountManager.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="accountManagerOperation"/>


6. Here's the sample AccountManagerImpl:

public class AccountManagerImpl implements AccountManager {
    /** Creates a new instance of AccountManagerImpl */
    public AccountManagerImpl() {

    private AccountHolderDAO accountHolderDAO;
    public AccountHolder createAccountHolder(AccountHolder accountHolder) throws BankException {
        return accountHolderDAO.create(accountHolder);

    public AccountHolderDAO getAccountHolderDAO() {
        return accountHolderDAO;

    public void setAccountHolderDAO(AccountHolderDAO accountHolderDAO) {
        this.accountHolderDAO = accountHolderDAO;

7. Here's the sample AccountHolderDAO:

public class AccountHolderDAO {
    /** Creates a new instance of AccountHolderDAO */
    public AccountHolderDAO() {
    private EntityManagerFactory emf;

    public EntityManagerFactory getEmf() {
        return emf;

    public void setEmf(EntityManagerFactory emf) {
        this.emf = emf;
    public AccountHolder create(AccountHolder newAccountHolder) throws BankException {
        try {
            // JTA Transaction assumed to have been started by AccountManager (Spring tx advice)
            EntityManager em = emf.createEntityManager();
            //em.getTransaction().begin(); - Not required
            //em.getTransaction().commit(); - Not required
            return newAccountHolder;
            // JTA Transaction will be completed by Spring tx advice
        } catch (Exception e) {
            throw new BankException("Account creation failed" + e.getMessage(), e);

You will have some other code accessing the Spring bean "accountManager" and invoke the createAccountHolder() with the required parameters. Things should work well.