2

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.

Sanne
  • 6,027
  • 19
  • 34
ziggy
  • 15,677
  • 67
  • 194
  • 287
  • A silly question perhaps, but how are you calling `updadeProduct`? Is it by interface? – Dan Jun 13 '12 at 14:21

2 Answers2

4

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().

Hasan Ceylan
  • 591
  • 3
  • 7
1

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

Sebastian Łaskawiec
  • 2,667
  • 15
  • 33
  • I have not configured a JTA datasource in Jboss. Which element needs to be removed? – ziggy Jun 13 '12 at 14:26
  • I was thinking about removing "non-jta-data-source". I noticed that your data source is used in "non-jta-data-source" as well as "jta-data-source". This is why I mentioned about changing "transaction-type" to JTA. – Sebastian Łaskawiec Jun 13 '12 at 17:16