我正在尝试在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
属性,数据没有提交给数据库。
发生了什么事?我究竟做错了什么?我错过了什么?
答案 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>
在这方面,尝试重新发明轮子毫无意义。