Spring只读事务将数据提交给DB

时间:2014-04-14 22:48:29

标签: java spring hibernate oracle11g

我正在尝试在Spring Framework Reference的第11.5.2项之后为服务方法实现read-only事务,但事务仍然会自动将数据提交到数据库。

我正在使用Spring 3.1.0.RELEASE,Hibernate 3.5.5-Final和Oracle 11g Express Edition 11.2.0.2.0版。这是我的设置:

建议,切入点,顾问和事务管理器的XML:

<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>

服务界面:

package my.example.service;

public interface MyService {

    void getFoo();

    void bar();
}

服务实施:

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");
    }
}

调用getFoo()bar()后,即使getFoo()标记为read-only,数据库也会更新。但如果我改变这两行:

<tx:method name="get*" read-only="true" />
<tx:method name="*"/>

为:

<tx:method name="*" read-only="true" />

这两种方法都尊重read-only属性,数据没有提交给数据库。

发生了什么事?我究竟做错了什么?我错过了什么?

2 个答案:

答案 0 :(得分:4)

我发现了read-only交易被覆盖的原因。在web.xml中声明了OpenSessionInViewFilter,以前的开发人员在加载用户及其在控制器/接口中的角色时用来阻止LazyInitializationException

以下是过滤器声明:

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

我通过配置过滤器让每个事务使用自己的会话(称为deferred mode)解决了这个问题。

以下是激活了deferred mode的过滤器声明:

<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>

请阅读过滤器的Javadoc中的NOTE。我的DAO类扩展了org.springframework.orm.hibernate3.support.HibernateDaoSupport,并且继承的方法getSession()getSessionFactory().getCurrentSession()返回的Hibernate会话的刷新模式设置为FlushMode.MANUAL,而不是FlushMode.NEVER },正如我在阅读this SO answer后所说的那样。

答案 1 :(得分:0)

为什么不在@Transactional注释上使用readOnly标志。

使用@Transactional(readOnly=true)注释您的方法,Hibernate将尝试以只读方式执行事务,并且(我认为,您可能需要仔细检查)如果尝试写入将抛出异常。< / p>

在这方面,尝试重新发明轮子毫无意义。