Why is my transaction not active? javax.persistence.TransactionRequiredException: Executing an update/delete query

22,219

Solution 1

When you mark a method as @Transactional you are counting on JTA, yet - as stated by altanis - yet you define your persistence unit's transaction type as RESOURCE_LOCAL that is not JTA.

1) If you would like to use container managed transactions then change the transaction type, define your datasource as JTA Datasource in JBoss and change non-jta-data-source to jta-data-source

2) If you would like to manage your own transactions then keep the persistence.xml and datasource definition as it is but before any persist, merge, remove operations start a transaction by calling entitymanager.getTransaction().begin() and at the end of business unit, call either entitymanager.getTransaction().commit() or entitymanager.getTransaction().rollback(). In this case since you are managing transactions yourself, then there seems to be no point in starting a JTA transaction with @Transactional in updateProduct().

Solution 2

try changing transaction-type="RESOURCE_LOCAL" to transaction-type="JTA" in persistence.xml. Also you might need to remove element from persistence.xml.

Share:
22,219
ziggy
Author by

ziggy

Updated on February 24, 2020

Comments

  • ziggy
    ziggy over 4 years

    I have a Spring Web Service (Spring-WS) application that i am trying to configure to use. The stack i am using is as follows

    Spring 3
    Spring-WS
    JPA with Hibernate as the provider
    JBoss 7.1*
    

    The application is configured as follows:

    persistence.xml

    <persistence-unit name="myPersistenceUnit" transaction-type="RESOURCE_LOCAL">
            <provider>org.hibernate.ejb.HibernatePersistence</provider>
            <jta-data-source>java:jboss/datasources/myDataSource</jta-data-source>
            <non-jta-data-source>java:jboss/datasources/myDataSource</non-jta-data-source>
            <class>myPackage.MyClass</class>
            <properties>
                <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect"/>           
                <property name="hibernate.connection.autocommit" value="true" />
                <property name="hibernate.hbm2ddl.auto" value="validate"/>
                <property name="hibernate.show_sql" value="false"/>
                <property name="hibernate.cache.use_second_level_cache" value="true"/>
                <property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.SingletonEhCacheProvider"/>
                <property name="hibernate.search.default.directory_provider" value="org.hibernate.search.store.FSDirectoryProvider"/>
                <property name="hibernate.search.default.indexBase" value="./lucene/indexes"/>
                <property name="hibernate.search.default.batch.merge_factor" value="10"/>
                <property name="hibernate.search.default.batch.max_buffered_docs" value="10"/>
            </properties>
        </persistence-unit>
    

    spring.xml - Entity Manger and Transaction manager

    <context:annotation-config/>
    
        <context:component-scan base-package="com.mypackage"/>
    
        <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
        <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
    
        <!-- Live database entity and transaction managers -->
        <bean id="entityManagerFactory"
            class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
            p:dataSource-ref="myDataSource">
    
            <property name="persistenceUnitName" value="myPersistenceUnit" />
        </bean>
    
        <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
            p:entityManagerFactory-ref="entityManagerFactory" />
    
        <tx:annotation-driven transaction-manager="transactionManager" />           
    

    Web.xml - To load the spring.xml file above

    <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                /WEB-INF/app-config.xml
                /WEB-INF/spring.xml
                /WEB-INF/spring-datasources.xml
             </param-value>   
         </context-param>
    

    spring-datasources.xml

    <jee:jndi-lookup id="myDataSource" jndi-name="java:jboss/datasources/myDataSource"/>
    

    In my DAO class i have the following definition for the entityManager.

    @PersistenceContext(type=PersistenceContextType.TRANSACTION, unitName="myPersistenceUnit")
    protected EntityManager entityManager;
    
    @Transactional
        public void updateProduct(Product product) {
    
            //  Save the document to the database
            update(product);
        }
    

    The update method above simply calls a generic method with a call to entityManager.merge(object);

    Now when i test the above i find that it works if i am reading from the database but it does not work if i am writing to the database (i.e. create or update). If i try to write to the i get the following exception:

    javax.persistence.TransactionRequiredException: Executing an update/delete query
       at org.hibernate.ejb.AbstractQueryImpl.executeUpdate(AbstractQueryImpl.java:96)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:597)
       at org.springframework.orm.jpa.SharedEntityManagerCreator$DeferredQueryInvocationHandler.invoke(SharedEntityManagerCreator.java:310)
       at $Proxy96.executeUpdate(Unknown Source)
    

    I am guessing the fact that i can read from the database it means that something is wrong in the configuration of the transaction manager. Any ideas?

    Edit

    OK i just re-read the above and noticed that the last bit is slightly wrong. The exception i have shown above only occurs if i use JPQL to issue an Update statement using entityManager.createQuery. If i try to update the entity using entityManager.merge() nothing actually happens. No exception is returned but the row is not updated.