在项目中配置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;
- }
- }