HibernateDaoSupport的子類在保存實(shí)體時(shí)拋出InvalidDataAccessApiUsageException異常,異常堆棧如下:
org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.
at org.springframework.orm.hibernate3.HibernateTemplate.checkWriteOperationAllowed(HibernateTemplate.java:1090)
at org.springframework.orm.hibernate3.HibernateTemplate$12.doInHibernate(HibernateTemplate.java:629)
at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:367)
at org.springframework.orm.hibernate3.HibernateTemplate.save(HibernateTemplate.java:627)
在網(wǎng)上搜了一下,其中大多數(shù)文章又是提OpenSessionInViewFilter又是提OpenSessionInViewInterceptor的,大多云山霧罩、不知所云。
其實(shí)這個(gè)異常的提示還是很明確的:在只讀模式下(FlushMode.NEVER/MANUAL)寫(xiě)操作不被允許:把你的Session改成FlushMode.COMMIT/AUTO或者清除事務(wù)定義中的readOnly標(biāo)記。
首先看一下我Spring的配置文件,為了減少篇幅,僅將與事務(wù)有關(guān)的一部分貼在下面:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans><!-- Transaction template for Managers, from:http://blog.exis.com/colin/archives/2004/07/31/concise-transaction-definitions-spring-11/ --><bean id="txProxyTemplate" abstract="true"class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"><property name="transactionManager"><!--org.springframework.orm.hibernate3.HibernateTransactionManager的Bean實(shí)例--><ref bean="gkgltransactionManager" /></property><property name="transactionAttributes"><props><prop key="save*">PROPAGATION_REQUIRED</prop><prop key="remove*">PROPAGATION_REQUIRED</prop><prop key="do*">PROPAGATION_SUPPORTS</prop><prop key="auto*">PROPAGATION_SUPPORTS</prop><!--對(duì)于其它方法要求事務(wù)并且是只讀的--><prop key="*">PROPAGATION_SUPPORTS,readOnly</prop></props></property></bean><!-- Generic manager that can be used to do basic CRUD operations on any objects --><bean id="manager" parent="txProxyTemplate"><property name="target"><bean class="com.neuqsoft.base.service.impl.BaseManager"><property name="dao"><ref bean="gkgldao" /></property></bean></property></bean></beans>
對(duì)于清除readOnly標(biāo)記是很簡(jiǎn)單的,只需把上述配置文件中txProxyTemplate Bean定義中的<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>中的readOnly及其前面的逗號(hào)去掉即可。
接下來(lái)我們討論把Session改成FlushMode.COMMIT/AUTO,下面是HibernateTemplate中checkWriteOperationAllowed方法的源碼:
protected void checkWriteOperationAllowed(Session session) throws InvalidDataAccessApiUsageException {if (isCheckWriteOperations() && getFlushMode() != FLUSH_EAGER &&session.getFlushMode().lessThan(FlushMode.COMMIT)) {throw new InvalidDataAccessApiUsageException("Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): "+"Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.");}}
通過(guò)閱讀這段代碼我們不難看出,在Java代碼中調(diào)用HibernateTemplate的save或者saveOrUpdate等涉及到寫(xiě)操作的方法之前需要把Session的刷新模式設(shè)置為FlushMode.COMMIT或更高的級(jí)別,或者把HibernateTemplate的刷新模式設(shè)置為FLUSH_EAGER,由于我們的Dao繼承自HibernateDaoSupport,所以設(shè)置Session刷新模式的語(yǔ)句如下:getSession().setFlushMode(FlushMode.COMMIT);
而設(shè)置HibernateTemplate刷新模式的語(yǔ)句如下:
HibernateTemplate tmp=getHibernateTemplate();tmp.setFlushMode(HibernateTemplate.FLUSH_EAGER);
只要在調(diào)用HibernateTemplate涉及到寫(xiě)操作的方法之前正確設(shè)置了HibernateTemplate或者Session的刷新模式,則上述異常不會(huì)再拋出。
聯(lián)系客服