使用Spring實現反應式事務(Reactive Transactions)
本文探討如何使用RDBC2或MongoDB來使用Spring Reactive的事務支援。
在還沒有加入響應式/反應式事務整合之間,Spring認為沒有必須進行Reactive事務管理,因此,Spring Framework不支援Reactive @Transaction。
隨著時間的推移,MongoDB開始支援MongoDB Server 4.0的多文件事務,R2DBC(反應式SQL資料庫驅動程式的規範)開始出現,最終在Template API中提供inTransaction(…) 方法作為執行原生本級事務的工作單元。
雖然將inTransaction(…)方法用於較小的工作塊很方便,但它並不反映Spring支援事務的方式。在使用指令式程式設計模型時,Spring Framework允許兩種事務管理安排:@Transactional和TransactionTemplate(宣告性的各自的程式化事務管理)。
這兩種事務管理方法都建立在PlatformTransactionManager管理事務資源事務的基礎之上。PlatformTransactionManager可以是Spring提供的事務管理器實現,也可以是基於J他的Java EE實現。
兩種方法的共同之處在於它們將事務狀態繫結到ThreadLocal儲存,這允許事務狀態管理而不傳遞TransactionStatus物件。事務管理應該在後臺以非侵入方式進行。因為我們沒有讓執行緒繼續在事務中繼續有作用工作的設想,因此ThreadLocal只在指令式程式設計中工作。
指令式程式設計事務管理工作機制
事務管理需要將其事務狀態與執行相關聯。在指令式程式設計中,這通常是ThreadLocal儲存 - 事務狀態被繫結到一個執行緒,假設前提是事務程式碼在容器呼叫它的同一個執行緒上執行。
反應式程式設計模型消除了命令式(同步/阻塞)程式設計模型的這一基本假設。仔細研究反應式執行情況,你會發現程式碼在不同的執行緒上執行。使用程式間通訊時,這會更加明顯。我們再也不能安全地假設我們的程式碼在同一個執行緒上完全執行了。
這種變化使的依賴ThreadLocal的事務管理實現無效。
我們需要一種不同的安排來反映事務狀態,而不是一直傳遞一個TransactionStatus物件。
關聯帶外資料並不是反應空間中的新要求。我們在其他領域遇到過這種要求,例如SecurityContextSpring Security for reactive方法安全性(僅舉一例)。Project Reactor是Spring自身構建其響應支援的反應庫,自3.1版本開始就為訂閱者的上下文提供了支援。
Reactor Context是替代ThreadLocal指令式程式設計的反應式程式設計,上下文允許將上下文資料繫結到特定的執行。對於反應式程式設計,這是一個Subscription。
Reactor Context允許Spring將事務狀態以及所有資源和同步繫結到特定的Subscription狀態。使用Project Reactor的所有反應程式碼現在都可以參與響應式事務。
反應性事務管理
從Spring Framework 5.2 M2開始,Spring通過ReactiveTransactionManagerSPI 支援響應式/反應式事務管理。
ReactiveTransactionManager是使用事務資源的反應式和非阻塞整合的事務管理抽象。它是一個會返回Publisher的反應式@Transactional方法元註解,使用TransactionalOperator實現可程式設計的事務管理。
兩個反應式事務管理器實現是:
- R2DBC通過Spring Data R2DBC 1.0 M2
- MongoDB通過Spring Data MongoDB 2.2 M4
讓我們來看看反應式式事務的樣子:
class TransactionalService { final DatabaseClient db TransactionalService(DatabaseClient db) { this.db = db; } @Transactional Mono<Void> insertRows() { return db.execute() .sql("INSERT INTO person (name, age) VALUES('Joe', 34)") .fetch().rowsUpdated() .then(db.execute().sql("INSERT INTO contacts (name) VALUES('Joe')") .then(); } } |
反應事務看起來非常類似於註釋驅動中的命令事務,主要的區別在於我們使用DatabaseClient,這是一個反應性資源抽象。所有事務管理都在幕後進行,利用Spring的事務攔截器和ReactiveTransactionManager。
Spring基於方法返回型別分辨要應用的事務管理型別:
- 方法返回一個Publisher型別:響應式事務管理
- 所有其他return型別:傳統的命令式事務管理
這種區別很重要,因為您仍然可以使用命令式元件,例如JPA或JDBC查詢,如果將這些查詢結果包裝成一個Publisher型別,Spring將應用反應而不是命令式事務管理,反應式事務管理就不會開啟ThreadLocal中繫結的JPA或JDBC所需的事務。
TransactionalOperator
下一步,讓我們看一下程式設計化事務管理TransactionalOperator:
ConnectionFactory factory = … ReactiveTransactionManager tm = new R2dbcTransactionManager(factory); DatabaseClient db = DatabaseClient.create(factory); TransactionalOperator rxtx = TransactionalOperator.create(tm); Mono<Void> atomicOperation = db.execute() .sql("INSERT INTO person (name, age) VALUES('joe', 'Joe')") .fetch().rowsUpdated() .then(db.execute() .sql("INSERT INTO contacts (name) VALUES('Joe')") .then()) .as(rxtx::transactional); |
上面的程式碼包含一些值得注意的元件:
- R2dbcTransactionManager:這是R2DBC的反應式事務管理器ConnectionFactory。
- DatabaseClient:客戶端使用R2DBC驅動程式提供對SQL資料庫的訪問。
- TransactionalOperator:此運算子將所有上游R2DBC釋出者與事務上下文相關聯。您可以使用操作員樣式as(…::transactional)或回撥樣式execute(txStatus -> …)。
訂閱後會懶惰地反應式事務,operator啟動事務,設定適當的隔離級別並將資料庫連線與其訂戶上下文相關聯。所有參與(上游)Publisher例項都使用一個上下文繫結事務連線。
Reactive-functional operator 鏈可以是線性的(通過使用單個Publisher)或非線性的(通過合併多個流)。Publisher使用operator風格樣式時,反應式事務將會影響所有上游。要將事務範圍限制為特定的Publishers 集合,請應用回撥樣式,如下所示:
TransactionalOperator rxtx = TransactionalOperator.create(tm); Mono<Void> outsideTransaction = db.execute() .sql("INSERT INTO person (name, age) VALUES('Jack', 31)") .then(); Mono<Void> insideTransaction = rxtx.execute(txStatus -> { return db.execute() .sql("INSERT INTO person (name, age) VALUES('Joe', 34)") .fetch().rowsUpdated() .then(db.execute() .sql("INSERT INTO contacts (name) VALUES('Joe Black')") .then()); }).then(); Mono<Void> completion = outsideTransaction.then(insideTransaction); |
在上面的示例中,事務管理僅限於在execute(…)裡面訂閱的Publisher例項。換句話說,事務是作用域的。execute(…)中Publisher例項參與事務,並且命名outsideTransaction的Publisher在事務之外執行其工作。
Spring Data MongoDB
R2DBC是Spring與反應式的整合之一。另一個事務整合是通過Spring Data MongoDB訪問MongoDB,您可以使用反應式程式設計來參與多文件事務。
Spring Data MongoDB是使用ReactiveMongoTransactionManager,這是一個ReactiveTransactionManager實現。它建立會話並管理事務,以便在託管事務中執行的程式碼參與多文件事務。
以下示例顯示了MongoDB的程式設計事務管理:
ReactiveTransactionManager tm = new ReactiveMongoTransactionManager(databaseFactory); ReactiveMongoTemplate template = … template.setSessionSynchronization(ALWAYS); TransactionalOperator rxtx = TransactionalOperator.create(tm); Mono<Void> atomic = template.update(Step.class) .apply(Update.set("state", …)) .then(template.insert(EventLog.class).one(new EventLog(…)) .as(rxtx::transactional) .then(); |
上面的程式碼設定一個ReactiveTransactionManager並用於TransactionalOperator在單個事務中執行多個寫操作。ReactiveMongoTemplate被配置為參與反應式交易。
相關文章
- 使用Spring Boot實現分散式事務Spring Boot分散式
- Laravel 之巢狀事務 transactions 實現Laravel巢狀
- Reactive Spring實戰 -- 響應式Kafka互動ReactSpringKafka
- Reactive Spring實戰 -- 響應式MySql互動ReactSpringMySql
- Reactive Spring實戰 -- 響應式Redis互動ReactSpringRedis
- 使用Spring Boot實現事務管理Spring Boot
- 使用Spring Boot實現Redis事務 | VinsguruSpring BootRedis
- Spring事務專題(四)Spring中事務的使用、抽象機制及模擬Spring事務實現Spring抽象
- Spring宣告式事務@Transactional使用Spring
- Spring宣告式事務的兩種實現方式Spring
- 【Spring】事務實現原理Spring
- Spring事務實現原理Spring
- Reactive Spring實戰 -- WebFlux使用教程ReactSpringWebUX
- Backpressure in Reactive Systems 響應式系統的反壓React
- 使用Spring Boot + Kafka實現Saga分散式事務模式的原始碼 - vinsguruSpring BootKafka分散式模式原始碼
- Spring Cloud Seata系列:基於AT模式實現分散式事務SpringCloud模式分散式
- 分散式事務(3)---RocketMQ實現分散式事務原理分散式MQ
- 使用Spring Boot反應式R2DBC實現PostgreSQL的CRUD操作原始碼 - RajeshSpring BootSQL原始碼
- 分散式事務(4)---RocketMQ實現分散式事務專案分散式MQ
- Spring事務專題(五)聊聊Spring事務到底是如何實現的Spring
- 分散式事務之Spring事務與JMS事務(二)分散式Spring
- [譯] Spring 的分散式事務實現 — 使用和不使用 XA — 第二部分Spring分散式
- [譯] Spring 的分散式事務實現-使用和不使用XA — 第三部分Spring分散式
- 【spring】事務底層的實現流程Spring
- 三 Spring 宣告式事務Spring
- Spring-宣告式事務Spring
- Spring宣告式事務控制Spring
- Reactive Spring實戰 -- 理解Reactor的設計與實現ReactSpring
- 認識 MongoDB 4.0 的新特性——事務(Transactions)MongoDB
- Spring Cloud Stream的函式式和響應式Reactive程式設計特點 - spring.ioSpringCloud函式React程式設計
- [譯] Spring 的分散式事務實現 — 使用和不使用 XA — 第一部分Spring分散式
- Spring的事務管理(二)宣告式事務管理Spring
- Spring Cloud Alibaba 使用Seata解決分散式事務SpringCloud分散式
- 分散式事務之資料庫事務與JDBC事務實現(一)分散式資料庫JDBC
- 使用CRDT實現分散式事務的資料推薦分散式
- node.js 中使用redis實現分散式事務鎖Node.jsRedis分散式
- Spring宣告式事務控制原理之宣告式事務的重要元件在AOP中的應用Spring元件
- spring宣告式事務管理配置Spring