如何使用Spring 4.0.6全局设置FlushMode for Hibernate 4.3.5.Final?

我正在尝试使用Hibernate 4.3.5.Final和Spring 4.0.6升级我们的应用程序。 我的应用程序中数据库写入操作的任何位置都会出现如下错误:

Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition. at org.springframework.orm.hibernate4.HibernateTemplate.checkWriteOperationAllowed(HibernateTemplate.java:1135) at org.springframework.orm.hibernate4.HibernateTemplate$26.doInHibernate(HibernateTemplate.java:826) at org.springframework.orm.hibernate4.HibernateTemplate.doExecute(HibernateTemplate.java:340) at org.springframework.orm.hibernate4.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:308) at org.springframework.orm.hibernate4.HibernateTemplate.deleteAll(HibernateTemplate.java:823) ... 

以下是sessionFactory和transactionManager的spring配置:

     com/mycompany/Person.hbm.xml     org.hibernate.dialect.HSQLDialect       

1:

为了全局设置flushMode以便应用程序以与以前相同的方式工作,我需要将flushMode设置为全局,因此我不想使用@Transactional(readOnly = false)方法。

2:

在下面的post中,有人建议将singleSession设置为false, Java / Hibernate – 在只读模式下不允许写入操作

Spring文档建议指定“singleSession”=“false”有副作用: http ://docs.spring.io/spring/docs/4.0.6.RELEASE/javadoc-api/org/springframework/orm/hibernate3/support /OpenSessionInViewInterceptor.html

3:

我在web.xml中看到了类似下面的一些建议,它允许你拦截hibernate3会话并提供一个版本的会话,例如flushMode.AUTO。 但是,当您使用org.springframework.orm.hibernate4.support.OpenSessionInViewFilter时,这在hibernate 4中不起作用。

  openSessionInViewFilter org.springframework.orm.hibernate3.support.OpenSessionInViewFilter  flushMode AUTO   

4:

下面建议的方法是使用JPA事务管理器,它遵循HibernateJpaDialect的复杂重复实现。 我目前没有使用JPA,这种方法似乎不够简单。 如何在配置文件中将刷新模式设置为“COMMIT”?

5:

我在Spring配置中尝试过以下内容(根据Spring ORM 4.0.5和Hibernate 4.3.5的建议- 无法保存到数据库 ),它似乎不起作用,人们建议使用web.xml方法: Spring而Hibernate突然将事务设置为readonly

      

题:

任何人都可以建议一个简单的方法来允许为Hibernate 4.3.5.Final和Spring 4.0.6设置FlushMode吗?

我最终用自定义实现覆盖了OpenSessionInViewFilter:

1:

web.xml中:

  openSessionInViewFilter com.mycompany.AutoFlushOpenSessionInViewFilter   openSessionInViewFilter /*   org.springframework.web.context.ContextLoaderListener  
  • Spring需要ContextLoaderListener才能工作。
  • AutoFlushOpenSessionInViewFilter用于拦截来自/ * url模式的请求

2:

AutoFlushOpenSessionInViewFilter:

 import org.hibernate.FlushMode; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.orm.hibernate4.support.OpenSessionInViewFilter; public class AutoFlushOpenSessionInViewFilter extends OpenSessionInViewFilter { protected Session openSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException { try { Session session = sessionFactory.openSession(); session.setFlushMode(FlushMode.AUTO); // This line changes the default behavior return session; } catch (HibernateException ex) { throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex); } } } 

3:

所有Spring bean都需要在Web应用程序上下文(web.xml)中注册:

  contextConfigLocation  classpath:appContext.xml ...   

4:

确保在需要使用时只从应用程序上下文中获取spring bean。 以下是如何举例: http : //sujitpal.blogspot.co.uk/2007/03/accessing-spring-beans-from-legacy-code.html

确保只创建了一个Spring bean的副本! 如果使用org.springframework.context.support.ClassPathXmlApplicationContext加载Spring bean,则filter将不会拾取这些bean。

5:

在我的例子中,还需要contextId

  contextId myApp Required contextId when filter is supplied  

否则我得到以下问题:

 2014-09-02 10:59:50 StandardContext[/myApp]Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener java.lang.NoSuchMethodError: javax.servlet.ServletContext.getContextPath()Ljava/lang/String; at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:384) at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306) at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3827) at org.apache.catalina.core.StandardContext.start(StandardContext.java:4343) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:823) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:807) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:595) at org.apache.catalina.core.StandardHostDeployer.addChild(StandardHostDeployer.java:903) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.apache.commons.beanutils.MethodUtils.invokeMethod(MethodUtils.java:216) at org.apache.commons.digester.SetNextRule.end(SetNextRule.java:256) at org.apache.commons.digester.Rule.end(Rule.java:276) at org.apache.commons.digester.Digester.endElement(Digester.java:1058) at org.apache.catalina.util.CatalinaDigester.endElement(CatalinaDigester.java:76) at org.apache.xerces.parsers.AbstractSAXParser.endElement(Unknown Source) ... 

如果有人有兴趣,以下是我的Ivy.xml中的内容

                

希望这有助于在升级Spring和Hibernate时遇到同样问题的任何人。