Spring read-only transaction committing data to the DB

hibernate, java, oracle11g, spring

Solution

I found out why the `read-only` transactions were being overriden. There is an OpenSessionInViewFilter declared in `web.xml`, which previous developers used to prevent `LazyInitializationException`s when loading the user and its roles in the controller/interface.

Here is the filter declaration:

<filter>
    <filter-name>openSessionInViewFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>

I worked around the issue by configuring the filter to let each transaction use its own session (called `deferred mode`).

Here is the filter declaration with `deferred mode` activated:

<filter>
    <filter-name>openSessionInViewFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
    <init-param>
        <param-name>singleSession</param-name>
        <param-value>false</param-value>
    </init-param>
</filter>

Please, read the NOTE in the filter's Javadoc. My DAO class extends `org.springframework.orm.hibernate3.support.HibernateDaoSupport`, and the the Hibernate Session returned by the inherited methods `getSession()` or `getSessionFactory().getCurrentSession()` had its flush mode is set to `FlushMode.MANUAL`, instead of `FlushMode.NEVER`, as I exptected after reading this SO answer.

Problem

I'm trying to implement a `read-only` transaction for a service method, following item 11.5.2 of the Spring Framework Reference, but the transaction still automatically commits data to the DB. I'm using Spring 3.1.0.RELEASE, Hibernate 3.5.5-Final and Oracle 11g Express Edition Release 11.2.0.2.0. Here is my setup: The XML for the advice, the pointcut, the advisor and the transaction manager: ``` <tx:advice id="transactionAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="get*" read-only="true" /> <tx:method name="*"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="myServiceMethods" expression="execution(* my.example.service.*.*(..))" /> <aop:advisor pointcut-ref="myServiceMethods" advice-ref="transactionAdvice" /> </aop:config> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> <!-- the sessionFactory bean declaration does not set the --> <!-- hibernate.connection.autocommit property as either true or false --> </bean> ``` The service interface: ``` package my.example.service; public interface MyService { void getFoo(); void bar(); } ``` The service implementation: ``` package my.example.service.impl; import my.example.dao.MyDao; import my.example.domain.MyEntity; import my.example.service.MyService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class MyServiceImpl implements MyService { @Autowired private MyDao dao; public void getFoo() { MyEntity example = this.dao.getMyEntity(1L); example.setSomeInteger(2); example.setSomeString("three"); } public void bar() { MyEntity example = this.dao.getMyEntity(4L); example.setSomeInteger(5); example.setSomeString("six"); } } ``` After calling either `getFoo()` or `bar()`, the DB is updated, even though `getFoo()` is marked as `read-only`. But if I change these two lines: ``` <tx:method name="get*" read-only="true" /> <tx:method name="*"/> ``` to: ``` <tx:method name="*" read-only="true" /> ``` both methods respect the `read-only` property and data does not get committed to the DB. What's going on? What am I doing wrong? What did I miss?

Original source

Related problems