2011-07-24 37 views
11

最近我一直有一個令人討厭的異常,經過對Google和這個論壇的一些研究後,我仍然沒有找到可以解決我的問題的答案問題。Java /休眠 - 寫操作不允許在只讀模式下

這裏的東西 - 有時候,我試圖更新或創建休眠一個新的對象時,出現以下錯誤:

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. 
at org.springframework.orm.hibernate3.HibernateTemplate.checkWriteOperationAllowed(HibernateTemplate.java:1186) 
at org.springframework.orm.hibernate3.HibernateTemplate$12.doInHibernate(HibernateTemplate.java:696) 
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:419) 
at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374) 
at org.springframework.orm.hibernate3.HibernateTemplate.save(HibernateTemplate.java:694) 

什麼是真正奇怪的是,該方法getHibernateTemplate().saveOrUpdate(object);更新對象有時當它會工作,但有時與同一個對象,並通過調用相同的方法它不起作用,但它似乎取決於我如何獲得對象的第一位。

例如:假設我有一個包含3個字段的表:id,type,length。可能發生的是,如果我通過id獲取對象並更新長度,那麼它將起作用。如果我通過類型獲取它並更新長度,那麼它將不起作用。所以,爲了避免這個問題,我一直在做的是獲取這個方法的對象,這個方法稍後不會導致問題,但是這會變得越來越討厭,試圖找到一種可行的方法。

此外,現在我嘗試創建一個對象時(但不是所有這些對象,只是在一個特定的表上),並且找不到解決方法。我試圖在交易中添加@Transactional(readOnly = false),但它沒有改變任何內容,並且顯示模式是說我不是隻讀的。

有什麼建議嗎?七月

編輯26日: 這裏的一些配置,以冬眠

<property name="hibernateProperties"> 
    <props> 
     <prop key="jdbc.fetch_size">20</prop> 
     <prop key="jdbc.batch_size">25</prop> 
     <prop key="cglib.use_reflection_optimizer">true</prop> 
     <prop key="hibernate.show_sql">true</prop> 
     <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> 
     <prop key="connection.autoReconnect">true</prop> 
     <prop key="connection.autoReconnectForPools">true</prop> 
     <prop key="connection.is-connection-validation-required">true</prop> 
    </props> 
</property> 

而且,如果它可以幫助

<property name="transactionAttributes"> 
    <props> 
     <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop> 
     <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop> 
     <prop key="execute*">PROPAGATION_REQUIRED</prop> 
     <prop key="add*">PROPAGATION_REQUIRED</prop> 
     <prop key="create*">PROPAGATION_REQUIRED</prop> 
     <prop key="update*">PROPAGATION_REQUIRED</prop> 
     <prop key="delete*">PROPAGATION_REQUIRED</prop> 
    </props> 
</property> 

八月的編輯31日相關: 班裏相關的代碼擴展HibernateDaoSupport,保存的對象是:

public void createObject(Object persisObj) { 
    getHibernateTemplate().save(persisObj); 
} 
+1

您是否在使用具有** READ_ONLY **模式的​​'@ Cache'?或者有一個方法/類在'@Transactional(readOnly = true)'註釋過的地方? 我自己遇到過這類問題,發現這兩個配置對這個錯誤起作用。大多數情況下,如果你加載一個對象,修改它並再次堅持。 我特別不喜歡使用'HibernateTemplate',那也可能是隱藏在後臺的一些配置。 如果你通過你的配置的一些片段,我可能會提供幫助。 –

+0

感謝T男抽出時間回覆。所以我在整個項目中搜索了@ Cache/@ Transactional中的任何一個,並且沒有這樣的事情(我從來沒有把它放在我的項目中)。我實際上沒有配置hibernate或寫入方法,但我現在將添加我的配置在帖子中。此外,創建某些對象時出現此錯誤,但不是全部(始終是相同的),因此它不僅與更新對象有關 – Guillaume

回答

6

我改變了單一會話屬性格式從視圖過濾器。問題解決:

<filter> 
    <filter-name>hibernateFilter</filter-name> 
    <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class> 
    <init-param> 
     <param-name>singleSession</param-name> 
     <param-value>false</param-value> 
    </init-param> 
    </filter> 
+0

仍然我的更新不工作! –

+1

我想'getHibernateTemplate()了getSessionFactory()的getCurrentSession()setFlushMode(FlushMode.AUTO);。'和我的問題解決了... –

10

使用Spring OpenSessionInViewFilter並試圖在Spring管理的事務之外執行持久性操作時,通常會看到該錯誤消息。該過濾器將會話設置爲FlushMode.NEVER/MANUAL(取決於您使用的Spring和Hibernate的版本 - 它們大致相同)。當Spring事務機制開始一個事務時,它將刷新模式更改爲「COMMIT」。交易完成後,根據需要將其設置爲「無論如何/手動」。如果你是絕對確定這沒有發生,那麼下一個最有可能的罪魁禍首是非線程安全使用會話。 Hibernate會話只能在一個線程中使用。如果它跨越線程之間,可能會發生各種混亂。請注意,從Hibernate加載的實體可以持有對其加載的會話的引用,並且可以通過線程處理該實體,從而也可以從另一個線程訪問該會話。

+0

感謝您的回答。您似乎對此有所瞭解,對於您的回答我有點困惑。所以我使用Eclipse進行開發,您認爲我應該怎麼做才能檢測/糾正問題?我能做些什麼來嘗試修復它? – Guillaume

+1

最佳啓動方式可能是在InvalidDataAccessApiUsageException中添加異常斷點,然後調試應用程序並使其發生。然後檢查堆棧以查看如何處理異常。尤其要檢查會話是如何以及在哪裏開啓的,以及是否開始交易。你可以從異常堆棧跟蹤中告訴它一些,但讓它住在調試器中更好。 –

+0

那麼我仍然堅持這一點。我試圖調試的東西,但真的沒有看到我能做些什麼。我沒有看到任何會議或任何內容。任何人都有建議? – Guillaume

5

我也偶然發現了這一點。我需要將Spring的OpenSessionInViewFilter中的刷新模式更改爲手動模式,並且突然間我開始得到這個異常。我發現這些問題在未註釋爲@Transactional的方法中發生,因此我猜Spring會將所有數據訪問代碼隱式地視爲只讀等方法。註解該方法解決了問題。

另一種方法是調用HibernateTemplate對象上的setCheckWriteOperations方法。

+0

所以我試圖@ Transactional'添加'的方法(見我的代碼編輯後):沒有任何改變。然後我試圖調用'setCheckWriteOperations(假);'保存之前,拿到了異常:'值java.sql.SQLException:連接是隻讀的。導致數據修改的查詢不被允許。然後我試圖刪除的'<支撐鍵=「獲得*」> PROPAGATION_REQUIRED,只讀'(見我的第一個編輯)和它的工作的',readOnly'一部分!有了這個,'@ Transactional'和檢查事情並不重要,但我想這不是一個好的解決方法。任何想法爲什麼發生這種情況? – Guillaume

+0

我真的沒有線索。你的get *屬性不會有任何機會創建一些新的對象?說,添加一個條目到日誌數據庫表或類似的東西? – alh84001

0

我有同樣的問題,並調查一天後,我發現以下的聲明

<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/> 

我刪除

mode="aspectj" 

和問題消失

+0

不幸的是我沒有TX:在我的任何配置文件註解驅動的標籤 – Guillaume

+0

也許你必須把它放在你的配置文件,因爲默認的方式,它有一些錯誤的屬性值事務管理。這個問題是錯誤配置的結果,你必須找到錯誤 – Mihai

4

嘗試使用此

hibernateTemplate = new HibernateTemplate(sessionFactory); 
hibernateTemplate.setCheckWriteOperations(false); 

錯誤應該消失的模板不檢查,如果您使用的是交易。

+1

但更新不工作! 。 –

+0

我想'getHibernateTemplate()了getSessionFactory()的getCurrentSession()setFlushMode(FlushMode.AUTO);'我的問題解決了。 –

4

使用以下bean for HibernateTemplate in application context

<bean id="template" class="org.springframework.orm.hibernate4.HibernateTemplate"> 
     <property name="sessionFactory" ref="mysessionFactory"></property> 
     <property name="checkWriteOperations" value="false"></property> 
     </bean> 
1

下面的一段代碼是爲我工作的。

hibernateTemplate = new HibernateTemplate(sessionFactory); 
hibernateTemplate.setCheckWriteOperations(false); 
5

添加

@Transactional 

的功能上面

1

你必須忘了@Transactional註釋添加到您的DAO服務類/方法,這會指定你的數據庫操作將被Spring處理管理交易。