我正在尝试按照Spring Framework Reference的第11.5.2项实现服务方法的只读事务,但事务仍然会自动将数据提交到数据库.
我正在使用Spring 3.1.0.RELEASE,Hibernate 3.5.5-Final和Oracle 11g Express Edition Release 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()被标记为只读,DB也会更新.但如果我改变这两行:
<tx:method name="get*" read-only="true" />
<tx:method name="*"/>
至:
<tx:method name="*" read-only="true" />
两种方法都遵循只读属性,数据不会提交给DB.
这是怎么回事?我究竟做错了什么?我错过了什么?
解决方法:
我发现为什么只读事务被覆盖.在web.xml中声明了一个OpenSessionInViewFilter,以前的开发人员在加载用户及其在控制器/接口中的角色时用来阻止LazyInitializationExceptions.
这是过滤器声明:
<filter>
<filter-name>openSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
我通过配置过滤器来解决这个问题,让每个事务都使用自己的会话(称为延迟模式).
这是激活延迟模式的过滤器声明:
<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,并且继承方法返回的Hibernate Session getSession()或getSessionFactory().getCurrentSession()将其flush模式设置为FlushMode.MANUAL,而不是FlushMode.NEVER,正如我在阅读this SO answer后所说的那样.