2014-09-02 41 views
4

我想用Hibernate 4.3.5.Final和Spring 4.0.6升級我們的應用程序。在我的數據庫的寫操作的應用程序的任何地方得到一個錯誤如下:如何在Spring 4.0.6中全局設置FlushMode for Hibernate 4.3.5.Final?

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) 
    ... 

的follwing是我的sessionFactory和transactionManager的彈簧配置:

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> 
    <property name="dataSource" ref="dataSource"/> 
    <property name="mappingResources"> 
    <list> 
     <value>com/mycompany/Person.hbm.xml</value> 
    </list> 
    </property> 
    <property name="hibernateProperties"> 
    <props> 
     <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop> 
    </props> 
    </property> 
</bean> 

<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> 
    <property name="sessionFactory" ref="sessionFactory"/> 
</bean> 

1:

在爲了全局設置flushMode,以便應用程序的工作方式與以前相同,我需要將flushMode設置爲全局AUTO,所以我不想使用@Transactional(readOnly = false)方法。

2:

在下面的柱,有人建議設置singleSession爲false, Java/Hibernate - Write operations are not allowed in read-only mode

春天單證表明,指定 「singleSession」= 「假」 有副作用: http://docs.spring.io/spring/docs/4.0.6.RELEASE/javadoc-api/org/springframework/orm/hibernate3/support/OpenSessionInViewInterceptor.html

3:

我已經在web.xml中看到了很多像下面這樣的建議,它允許你截取hiberna te3會話並提供與例如會話的版本flushMode.AUTO。但是,在使用org.springframework.orm.hibernate4.support.OpenSessionInViewFilter時,這在hibernate 4中不起作用。

<filter> 
    <filter-name>openSessionInViewFilter</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> 

4:

提出這一方法下面是使用JPA事務管理器,它遵循一個複雜的重新實現HibernateJpaDialect的。我目前不使用JPA,這種方法似乎不夠簡單。 How do I set flush mode to "COMMIT" in my configuration files?

5:

我已經試過有在我的Spring配置如下(以下上Spring ORM 4.0.5 and Hibernate 4.3.5 - Cant save to database建議), 它似乎並沒有工作,人建議使用web.xml方法: Spring and Hibernate suddenly set the transaction to readonly

<tx:advice id="transactionAdvice" transaction-manager="transactionManager" > 
    <tx:attributes> 
    <tx:method name="*" read-only="false"/> 
    </tx:attributes> 
</tx:advice> 

問:

任何人都可以提出一個簡單的方法來允許爲Hibernate 4.3.5.Final和Spring 4.0.6設置FlushMode嗎?

+0

如果沒有設置清洗模式,我懷疑是錯誤的或缺少事務管理。你有'HibernateTransactionManager'這個事實並不意味着你有正確的tx設置。也只有在沒有''的情況下添加''才能應用它幾乎沒有用處。 – 2014-09-02 10:30:07

+0

@ M.Deinum感謝您的評論。在我的情況下,我需要在應用程序中使用FlashMode.AUTO(這是舊版Hibernate 3.0.5的默認版本)來鏡像以前的行爲。您的回答允許我進一步調查更清潔的解決方案(如果將全局只讀設置爲全局滿足我們的應用程序的需要)。 – Max 2014-09-03 11:58:01

回答

2

我結束了壓倒一切的OpenSessionInViewFilter與自定義實現:

1:

的web.xml:

<filter> 
    <filter-name>openSessionInViewFilter</filter-name> 
    <filter-class>com.mycompany.AutoFlushOpenSessionInViewFilter</filter-class> 
</filter> 

<filter-mapping> 
    <filter-name>openSessionInViewFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 

<listener> 
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
</listener> 
  • 的ContextLoaderListener需要Spring協同工作。
  • 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文件)中註冊:

<context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value> 
    classpath:appContext.xml 
    ... 
    </param-value> 
</context-param> 

4:

只有從應用程序上下文確保你得到你的春天豆,當您需要使用它們。以下是一個示例: http://sujitpal.blogspot.co.uk/2007/03/accessing-spring-beans-from-legacy-code.html

確保只有一個正在創建的Spring bean副本! 如果使用org.springframework.context.support.ClassPathXmlApplicationContext加載Spring bean,則這些bean將不會被過濾器拾取。

5:

在我的情況下,CONTEXTID還需要

<context-param> 
    <param-name>contextId</param-name> 
    <param-value>myApp</param-value> 
    <description>Required contextId when filter is supplied</description> 
</context-param> 

否則我得到以下問題:

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 4.0.6.RELEASE --> 
<dependency org="org.springframework" name="spring-aop" rev="4.0.6.RELEASE" conf="compile->master,sources,javadoc"/> 
<dependency org="org.springframework" name="spring-beans" rev="4.0.6.RELEASE" conf="compile->master,sources,javadoc"/> 
<dependency org="org.springframework" name="spring-core" rev="4.0.6.RELEASE" conf="compile->master,sources,javadoc"/> 
<dependency org="org.springframework" name="spring-expression" rev="4.0.6.RELEASE" conf="compile->master,sources,javadoc"/> 
<dependency org="org.springframework" name="spring-context" rev="4.0.6.RELEASE" conf="compile->master,sources,javadoc"/> 
<dependency org="org.springframework" name="spring-jdbc" rev="4.0.6.RELEASE" conf="compile->master,sources,javadoc"/> 
<dependency org="org.springframework" name="spring-orm" rev="4.0.6.RELEASE" conf="compile->master,sources,javadoc"/> 
<dependency org="org.springframework" name="spring-tx" rev="4.0.6.RELEASE" conf="compile->master,sources,javadoc"/> 
<dependency org="org.springframework" name="spring-web" rev="4.0.6.RELEASE" conf="compile->master,sources,javadoc"/> 
<dependency org="aopalliance" name="aopalliance" rev="1.0" conf="compile->master,sources,javadoc"/> 

<!--Hibernate 4.3.5--> 
<dependency org="org.hibernate" name="hibernate-core" rev="4.3.5.Final" conf="compile->master,compile,sources"/> 
<dependency org="net.sf.ehcache" name="ehcache-core" rev="2.4.8" conf="compile->master,sources,javadoc"/> 
<dependency org="org.slf4j" name="slf4j-api" rev="1.7.5" conf="compile->master,sources,javadoc"/> 

希望這可以幫助任何人在升級Spring和Hibernate時遇到同樣的問題。

+1

在'OpenSessionInViewFilter'中的刷新模式從來沒有(或手動)的原因:)。通常,當你有適當的tx管理時,事務管理器會將其設置爲臨時AUTO,直到事務結束。因此,我的建議是,這或多或少表明您在yuor應用程序中存在錯誤或缺席tx-management。 – 2014-09-03 12:05:38

+0

嗨@ M.Deinum,謝謝你的回答。這是否意味着現在Spring和Hibernate默認情況下執行只讀模式(因爲每個寫訪問默認都會得到異常)?如果是這種情況,禁用它並不覺得我們應該參與交易管理,對吧?我不希望始終啓用事務功能並將@Transactional(readOnly = false)添加到每個更新和刪除。如果您或任何人都可以將我指向一份關於如何正確實現hibernate 4的寫入權限的官方文檔,那將非常感謝!如果交易是要走的路,那很好。 – Max 2014-09-04 15:50:41

+0

與此同時,我會做更多的挖掘自己... – Max 2014-09-04 15:58:08

相關問題