存档

‘Spring’ 分类的存档

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.

2009年12月31日 IT北瓜 没有评论

昨天遇到这个异常“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>

分类: Hibernate, Java, Spring 标签:

Hibernate3.3.2+Spring2.5.6+Struts2.1.6整合异常解决——不断更新

2009年9月24日 IT北瓜 5 条评论

1、org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ’sessionFactory’ is defined

异常说明:sessionFactory bean未定义

异常原因:applicationContext.xml配置文件中使用其他名字sessionFactory

<property name="sessionFactory">
    <ref bean="dmccSessionFactory"/>
</property>

上面的代码中bean=”dmccSessionFactory”,这是造成异常的原因。这里用了别名,而不是默认的bean=”sessionFactory”。这种情况下在web.xml文件中配置OpenSessionInViewFilter则需要对使用的别名进行声明。

<filter>
    <description>处理Hibernate的懒加载问题</description>
    <filter-name>hibernateFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
    <init-param>
        <description>默认情况下,这个Filter会在Spring的bean池中找一个叫做sessionFactory的bean。如果使用了其他名字的SessionFactory,则应该在这里 指定这个名字。</description>
        <param-name>sessionFactoryBeanName</param-name>
        <param-value>dmccSessionFactory</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>hibernateFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

2、

ERROR – failed to lazily initialize a collection of role: leeo.pojo.TPermission.roles, no session or session was closed

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: leeo.pojo.TPermission.roles, no session or session was closed

异常说明:session已关闭,无法初始化懒加载数据集role

异常原因:Hibernate映射文件中配置了lazy="true",同时也启用了OpenSessionInViewFilter。当实现ajax检测role名称是否可用时报以上异常,我这里检测role名称是利用json格式返回数据的。json返回数据的特点是:如果action中的属性有get()方法并且该属性没有transient修饰,那么json就会将其返回。在我的TRoleAction中有private TRole role;并且role有get()方法,所以在检测名称是否可用后返回的json数据中会将这一属性返回,但是检测名称的可用性根本不需要用到这个属性,异常就是由于启用懒加载机制下json中返回role这个属性需要查询数据库,而这时session已经关闭,因此报异常。

解决方法:用transient对role属性进行修饰,即:private transient TRole role;这样json就不会将其返回,因为也不用再次查询关联数据不会出现session已关闭的异常。