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.
昨天遇到这个异常“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.”大概意思是说试图在只读模式下向数据库插入内容。由于出现这个异常的时候刚好要下班了,所以今天才把这个异常解决了,在这里记录一下。
由于博客上没有装代码高亮插件,都是用Windows Live Writer写文章,现在的这个电脑上没安装Windows Live Writer,所以一下内容引用代码的部分就没办法高亮显示了,不过涉及的代码不多,讲究着吧~~~
问题分析:上面的异常总的来说是由于lazy机制引起的,我们知道懒加载问题一般都是通过配置OpenSessionInViewFilter来解决。原先web.xml中配置OpenSessionInViewFilter部分的代码如下:
<filter>
<description>处理Hibernate的懒加载问题</description>
<filter-name>hibernateFilter</filter-name>
<filter-class>
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
解决方法:其实异常信息中已经很清楚的告诉我们解决方法了,异常中说到需要把session改为FlushMode.COMMIT(或者FlushMode.AUTO),抑或去掉Spring事务配置中的readOnly。这里Leeo选择将session改为FlushMode.COMMIT的方式。具体做法是自己写一个类继承org.springframework.orm.hibernate3.support.OpenSessionInViewFilter,代码如下:
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.orm.hibernate3.SessionFactoryUtils;public class OpenSessionInViewFilter extends
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter {
/**
* we do a different flushmode than in the codebase
* here
*/
protected Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
Session session = SessionFactoryUtils.getSession(sessionFactory, true);
session.setFlushMode(FlushMode.COMMIT);
return session;
}
/**
* we do an explicit flush here just in case
* we do not have an automated flush
*/
protected void closeSession(Session session, SessionFactory factory) {
session.flush();
super.closeSession(session, factory);
}}
然后只要把原先web.xml中的
<filter-class>
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
</filter-class>
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter改为刚刚写的类的包路径就可以了,即:
<filter-class>
com.frscs.util.OpenSessionInViewFilter
</filter-class>