2015-11-27 73 views
0

背景使用SERIALIZABLE事務隔離帶露天

露天使用默認的數據庫事務隔離,這對於我們的Oracle數據庫READ_COMMITED。我正在研究一個項目,其中不可重複和幻影讀取可能是一個主要問題,所以我正在研究使用SERIALIZABLE事務隔離來避免這種情況。

一方面,我們將有一個自定義API服務,將更改分組爲原子事務 - 基本上是對文檔的CRUD操作。另一方面,我們將有後臺進程更新並行運行的這些文檔的元數據。

這些操作將使用事務性元數據查詢,因爲通過將最終一致的SOLR查詢添加到組合中不會使事情進一步複雜化。

目標是在API服務運行時能夠進行主要的元數據模型遷移。爲了這個問題的目的,我將使用一個屬性作爲例子,但是IRL會有這種變化。例如,我們目前有一個帶有約束的元數據字段:mymodel:doctypes1。但是我們需要重新映射mymodel中的值:doctypes1到一個具有不同約束的新字段:mymodel:doctypes2。 (不要問我爲什麼,我無法控制這個決定,我個人質疑這種改變的智慧)。

我READ_COMMITTED隔離的理解告訴我,在這種情況下,我們有以下的情況很容易:

  • 後臺進程啓動一個事務,並讀取 爲MyModel的價值:doctypes1。
  • API在後臺進程提交之前在mymodel:doctypes1 中寫入更改。
  • 後臺進程根據mymodel:doctypes1的原始值更新myModel:doctypes2的值 。

這兩個值現在是不一致的:我相信這個錯誤被稱爲不可重複讀取。

的問題

會設置Oracle數據庫SERIALIZABLE防止這個問題? Alfresco正在使用Spring交易。我的理解是,使用Spring事務進行可序列化的tx隔離可以防止此問題「透明地」發生。

有沒有人有任何真正的世界經驗設置Alfresco數據庫SERIALIZABLE?你是否試圖解決類似的問題?它有用嗎?它對你有什麼樣的性能影響?

非常感謝您分享您的經驗!

+0

如果您在使用Oracle和Alfresco,那麼您使用的是付費的Alfresco One Enterprise。這意味着你得到了支持 - 只要給他們一個戒指/提高一張票,他們就會讓你聯繫到一小撮真正認識這些東西的Alfresco工程師! – Gagravarr

回答

2

Axel Faust在Alfresco論壇幫助我解決了這個問題,指出RetryingTransactionHelper強制執行樂觀鎖定並在兩個事務重疊的情況下重試。如果你對此感到好奇,我會推薦他的帖子。

https://forums.alfresco.com/forum/developer-discussions/repository-services/using-serializable-transaction-isolation-alfresco

只是爲了確保我做了一個小樣機挑起ConcurrencyException並檢查它確實表現正常。

我使用一個主類發送了同一節點的線程池49次更新:

for (int i=0; i < 50; i++) { 
     TestIncrementer ti = new TestIncrementer(node); 
     threadPoolExecuter.submit(ti); 
    } 

我只是增量讀取現有的標題,隨機睡,然後添加到它。

int hash = RetryingTransactionHelper.getActiveUserTransaction().hashCode(); 
    log.debug("Thread id: " + Thread.currentThread().getId() + " tx " + hash); 
    String title = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_TITLE); 
    Thread.sleep(Math.round(Math.random()* 1000)); 
    nodeService.setProperty(nodeRef, ContentModel.PROP_TITLE, title + "1"); 
    log.debug("Title: " + title); 

正如預期的那樣,我看到併發異常和重試:

Transaction commit failed: 
    Thread: defaultAsyncAction4 
    Txn: UserTransaction[[email protected]65b249f2, status=0] 
    Iteration: 8 
    Exception follows: 
org.springframework.dao.ConcurrencyFailureException: Failed to update node 126094 

但他們越來越重試。

最後一次重試離開節點正好有49個聚合!這正是需要發生的事情。

結論是,如果您將RetryingTransactionHelper用於後臺進程,那麼更改數據庫隔離絕對不是必需的,或者甚至是不可取的。