JTA EntityManager cannot use getTransaction() [Spring + Hibernate + EntityManager]

13,894

Solution 1

Remove the jta-datasource from persitence.xml, configure datasource as a bean j2ee:jdni-lookup and inject it into the LocalContainerEntityManagerFactoryBean

Remove this from persistence.xml

<jta-data-source>java:/TEST_DS</jta-data-source>

Configure the transaction-type to resource local

 <persistence-unit name="TEST_DS" transaction-type="RESOURCE_LOCAL">

Change to your beans.xml

<j2ee:jndi-lookup id="dataSource"  jndi-name="java:/TEST_DS"/>

 <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
   <property name="dataSource" ref="dataSource"/>
</bean>

Solution 2

First of all I want to tell you I had the same problem. Researching about that I found this page with your post and the answer by "gkamal".

I think that the answer comes to say that if you are trying to use "global" JTA transaction in your application and it doesn't work then don't use it, use in its place a "local" JDBC transaction.

But if you need to use global JTA transaction then you must use it.

Well I am going to give you the solution I found in my resarch.

There are properties that are application server dependent. I use glassfish and this solution works fine, but I think you are using JBOSS (due to the value you are using in the jta-data-source in your persistence.xml) I will write the values for a JBOSS AS, but in JBOSS AS I don't prove it, I just prove it only in glassfish.

In your persistence.xml you have to put another property:

<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossStandAloneJtaPlatform"/>

The value of this property is AP server dependent.

In your beans.xml file you have to take a look in the entity manager factory and transaction manager. Morover you have indicate in your web.xml which persistence units you are referencing in your application.

beans.xml

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="TEST_DS"/>
</bean>

In your transaction manager you are using entity manager factory but you don't have to do that. You have to indicate the transaction manager and user transaction used by your app server, this way

<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">
        <property name="transactionManagerName" value="java:appserver/TransactionManager"/>
        <property name="userTransactionName" value="java:comp/UserTransaction"/>
    </bean>

The values of those properties are app server dependent (I use glassfish). I think you have to use the values for jboss ap:

 <property name="transactionManagerName" value="java:/TransactionManager"/>
        <property name="userTransactionName" value="UserTransaction"/>

But I didn't prove it.

Last, in glassfish I have to put in beans.xml (and I don't know why) the following bean (I think in jboss ap it isn't necessary but you might prove it)

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" > 
        <property name="persistenceUnits"> 
            <map> 
                <entry key="TEST_DS" value="persistence/TEST_DS"/> 
            </map> 
        </property> 
    </bean> 

In your web.xml you need reference the persistence units your application will use.

<persistence-unit-ref>
    <persistence-unit-ref-name>persistence/TEST_DS</persistence-unit-ref-name>
    <persistence-unit-name>TEST_DS</persistence-unit-name>
</persistence-unit-ref>

I hope that the solution is of help for you. It works for me.

Share:
13,894
Higher-Kinded Type
Author by

Higher-Kinded Type

Updated on July 28, 2022

Comments

  • Higher-Kinded Type
    Higher-Kinded Type almost 2 years

    I am using Spring + JPA + Hibernate + EntityManager to talk to the database. I am getting 'A JTA EntityManager cannot use getTransaction()' error. Please provide your insights and help me resolve the issue.

    beans.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans default-autowire="byName"
        ... xmlns definitions...
          xsi:schemaLocation="...">
    
        <context:component-scan base-package="com.mycompany.myproject" />
    
        <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" />
        <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
    
        <bean id="myDAO" class="com.mycompany.myproject.dao.myDAO" />
    
        <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
            <property name="entityManagerFactory" ref="entityManagerFactory" />
        </bean>
    
        <tx:annotation-driven />
    </beans>
    

    persistence.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence ... xmlns definitions xsi:schemaLocation="..." version="1.0">
        <persistence-unit name="TEST_DS">
            <provider>org.hibernate.ejb.HibernatePersistence</provider>
            <jta-data-source>java:/TEST_DS</jta-data-source>
            <class>com.twinspires.exchange.model.Test</class>
            <properties>
                <property name="hibernate.archive.autodetection" value="class, hbm" />
                <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
                <property name="hibernate.hbm2ddl.auto" value="validate" /> <!-- create-drop update -->
                <property name="hibernate.cache.use_query_cache" value="true" />
                <property name="hibernate.show_sql" value="true" />
                <property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider" />
                  <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>             
            </properties>
        </persistence-unit>
    </persistence>
    

    Exception Stack Trace (Excerpt)

    15:47:43,340 INFO  [STDOUT] DEBUG: org.springframework.transaction.annotation.AnnotationTransactionAttributeSource - Adding transactional method 'getName' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
    15:47:43,343 INFO  [STDOUT] DEBUG: org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'transactionManager'
    15:47:43,356 INFO  [STDOUT] DEBUG: org.springframework.orm.jpa.JpaTransactionManager - Creating new transaction with name [com.twinspires.exchange.dao.PicDAO.getName]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
    15:47:44,114 INFO  [STDOUT] DEBUG: org.springframework.orm.jpa.JpaTransactionManager - Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl@c629e5] for JPA transaction
    15:47:44,124 INFO  [STDOUT] DEBUG: org.springframework.orm.jpa.JpaTransactionManager - Could not rollback EntityManager after failed transaction begin
    15:47:44,125 INFO  [STDOUT] java.lang.IllegalStateException: A JTA EntityManager cannot use getTransaction()
    15:47:44,125 INFO  [STDOUT]     at org.hibernate.ejb.AbstractEntityManagerImpl.getTransaction(AbstractEntityManagerImpl.java:818)
    15:47:44,126 INFO  [STDOUT]     at org.springframework.orm.jpa.JpaTransactionManager.closeEntityManagerAfterFailedBegin(JpaTransactionManager.java:412)
    15:47:44,127 INFO  [STDOUT]     at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:381)
    15:47:44,128 INFO  [STDOUT]     at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371)
    15:47:44,129 INFO  [STDOUT]     at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:335)
    15:47:44,129 INFO  [STDOUT]     at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:105)
    15:47:44,130 INFO  [STDOUT]     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    15:47:44,131 INFO  [STDOUT]     at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    15:47:44,131 INFO  [STDOUT]     at $Proxy175.getName(Unknown Source)
    

    Folowing is my dao class:-

    public class MyDao implements IMyDao {
          @PersistenceContext(unitName = "TEST_DS")
          private EntityManager entityManager;
    
          @Transactional
          public String getName() {            
                final Query query = entityManager.createQuery("from TestTable");
                final Object obj = query.getResultList().get(0);
                return obj == null ? "Empty" : (String) obj;
          }
    }
    

    Your help highly appreciated.