在项目中配置OpenSessionInViewFilter后,首先会出现的问题:
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.
这个是因为OpenSessionInViewFilter在getSession的时候,会把获取回来的session的flushMode 设为FlushMode.NEVER。然后把该sessionFactory绑定到TransactionSynchronizationManager,使request的整个过程都使用同一个session。
FlushMode.NEVER模式不具备写操作,可以把session配置为FlushMode.AUTO,如在web.xml中配置:
<filter>
<filter-name>OpenSessionInView</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>flushMode</param-name>
<param-value>AUTO</param-value>
</init-param>
</filter>
其次,会遇到的另外一个问题是页面更新操作,因为这个流程是:首先查询取得数据库中的记录,修改客户端改变的属性,更新这个实体类。这是通过以上配置OpenSessionInViewFilter,在session更新实体类之前,session已经存在一个实体类,与客户端传过来的需要修改的实体类会发生冲突,以致更新失败。这个可以通过配置singleSession=false解决。也可以通过重写OpenSessionInViewFilter类的getSession及closeSession方法实现,如:
public class MyOpenSessionInViewFilter extends OpenSessionInViewFilter{
@Override
protected void closeSession(Session session, SessionFactory sessionFactory) {
session.flush();
session.getTransaction().commit();
super.closeSession(session, sessionFactory);
}
@Override
protected Session getSession(SessionFactory sessionFactory)
throws DataAccessResourceFailureException {
Session session = SessionFactoryUtils.getSession(sessionFactory, true);
session.beginTransaction();
FlushMode flushMode = getFlushMode();
if (flushMode != null) {
this.setFlushMode(FlushMode.AUTO);
}
return session;
}
}