使用 Spring Data 進行 MongoDB 4.0 事務處理


使用 Spring Data 進行 MongoDB 4.0 事務處理

原文鏈接:http://spring.io/blog/2018/06/28/hands-on-mongodb-4-0-transactions-with-spring-data

作者:christophstrobl

譯者:hh23485

在 MongoDB 4.0 中,ACID 事務已經用於 Document 的存儲,強制維護全執行或全不執行的數據一致性狀態。所以讓我們直接在 synchronous 模型和 reactive 執行模型中驗證該特性。

在撰寫本文時,MongoDB 的多文檔事務在單副本集中受支持,並且給用戶的感受像是在使用關系型數據庫的事務一樣。看到驅動程序提供的 API 立刻會感覺到回到家里一樣。

try (ClientSession session = client.startSession()) { session.startTransaction(); try { collection.insertOne(session, documentOne); collection.insertOne(session, documentTwo); session.commitTransaction(); } catch (Exception e) { session.abortTransaction(); } } 

邏輯會話建立在 MongoDB的基礎上,當然,事務,當然還有事務構建了基礎。

邏輯會話通過幫助跨分布式節點協調操作來為MangoDB的因果一致性和事務建立基礎。客戶端從 client.startSession() 中獲取會話,會話的生命周期不應過長,在不再使用的時候應該立刻關閉它。所以確保使用 close() 來關閉客戶端會話。

在底層的協議層,上面的代碼片段將會轉變為如下一系列命令,你可以清楚的發現在每個命令中都包含會話(lsid)。startTransaction 標志位將會與第一個命令一起發送,表示事務的開始。在事務完成后,發送commitTransaction 表示事務的提交。

{ insert: "col", ordered: true, $db: "db", $clusterTime: { … }, lsid: { id: { $binary: { base64 : "I3M7Nj…", … } } }, txnNumber: 1, startTransaction: true, documents: [ { … } ] } { insert: "col", ordered: true, $db: "db", $clusterTime: { … }, lsid: { id: { $binary: { base64 : "I3M7Nj…", … } } }, txnNumber: 1, autocommit: false, documents: [ { …} ] } { commitTransaction: 1, $db: "admin", $clusterTime: { … }, lsid: { id: { $binary: { base64 : "I3M7Nj…", … } } }, txnNumber: 1 } 

隨着即將發布的 Spring Data Lovelace 版本,MongoDB 模塊將提供對 synchronous 和 reactive 事務的支持。

我們從 synchronous 模式開始,你可以能已經非常熟悉 Spring 框架對事務的支持 (Spring Framework’s transaction support) 。因此,一個 MongoTransactionManager 的存在並不令人吃驚。該事務管理器是在命令式世界中基於注解的事務支持的入口。

現在,因為 MongoDB 在早期版本中不支持事務,你必須明確的在 ApplicationContext 中注冊 MongoTransactionManager 。如果你這樣做的話,MongoTemplate 將會開始參與管理事務。這是一個你需要記住的要點。下面的例子展示了你應該如何配置事務管理器。

@Configuration class Config extends AbstractMongoConfiguration { @Bean MongoTransactionManager transactionManager(MongoDbFactory dbFactory) { return new MongoTransactionManager(dbFactory); } } @Service class DocumentService { private final MongoOperations operations; DocumentService(MongoOperations operations) { this.operations = operations; } @Transactional void insertDocuments() { operations.insert(documentOne); operations.insert(documentTwo); } } 

非常直播的操作是吧?但是,這里有一些隱含的缺點。 集群環境下的事務支持在下一個 MongDB 的 release 主要版本中才會支持,因此在您使用時會發生錯誤。此外,作為一個 MongoDB 的用戶,你可能已經習慣了他提供的所有的便利,但一些特性在事務中無法使用了,包括了幾乎所有的元命令,創建集合,索引以及受此使用集合時隱式創建集合。為了避免錯誤和折騰,請務必設置所需的結構。此外,某些命令可能還會有一些不同。例如使用集合集合統計信息的 count 命令可能在事務中並不准確。命令將會出錯並且需要使用聚合計數文檔,當前的驅動已經提供一個替代方法 countDocuments 來利用聚合策略解決這個問題。

考慮到這一點,讓我們繼續進行 reactive 使用的部分。

在 MongoDB的ReactiveStreams驅動程序 提供了一個反應切入點多文檔交易。將本機驅動程序管道Publisher化為 Reactor 類型可讓您表達事務用法,如下所示:

Mono.from(client.startSession()).flatMap(session -> {

  session.startTransaction();

  return Mono.from(collection.insertOne(session, documentOne)) .then(Mono.from(collection.insertOne(session, documentTwo))) .onErrorResume(e -> Mono.from(session.abortTransaction()) .then(Mono.error(e))) .flatMap(val -> Mono.from(session.commitTransaction()) .then(Mono.just(val))) .doFinally(signal -> session.close()); }); 

不管事務的結果是成功還是回滾,我們都需要保證事務的終止。因此,onErrorResume(...) 保證了事務在失敗的時候可以回滾,然后在 flatMap(...) 中提交,這兩個階段都保存了主流 (main flow) 的結果或錯誤。
不同於 sync 部分,截止撰稿時還沒有 reactive 模型可用的事務管理器能夠讓你通過注解 @Transactional 那樣簡單的完成事務工作。
相反,你需要通過 ReactiveMongoTemplate.inTransaction(...) 獲取一個 transaction 閉包。它在保持主流 (main flow) 結果的同事負責所有必需的會話,提交和終止操作。回調方法中的操作在MongoDB事務中執行,而外部的處理步驟將不會影響事務。這意味着閉包之外的處理錯誤不會導致事務終止,就像下面的例子描述的那樣。

template.inTransaction().execute(action ->

    // All code in here runs inside the transaction action.insert(documentOne).then(action.insert(documentTwo) ).flatMap(val -> { // An exception here does not affect the transaction }); 

在這個例子中,你能夠通過流訪問到 ClientSession,它存放在 Reactor 的 Context 中,並且你可以通過 ReactiveMongoContext.getSession() 來獲取它。

最后一件事情:我們非常高興你能夠嘗試並且給我們提供一些反饋,所以請查看 Spring Data Examples,您可以在其中找到相關的 項目

如果你想要學習更多有關 Spring Data 或者通用的 Spring eco-system,即將在華盛頓召開的 SpringOne Platform 會議對您來說是一個非常好的機會。查看會話並注冊。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM