Does Spring Framework support Reactive @Transaction?

反应性编程模型消除了命令式(同步/阻塞)编程模型的基本假设。仔细看看反应性执行,我们可以看到代码在不同的线程上执行。当使用进程间通信时,这一点更加明显。我们不能再安全地假设我们的代码完全在同一个线程上执行。
Reactive programming models remove this fundamental assumption of imperative (synchronous/blocking) programming models. Taking a closer look at reactive execution, we can observe that code gets executed on different threads. This gets more visible when using inter-process communication. We can no longer safely assume that our code is fully executed on the same thread.

Reactor上下文是响应式编程,就像ThreadLocal是命令式编程一样:上下文允许将上下文数据绑定到特定的执行。对于响应式编程,这是一种订阅。Reactor上下文允许Spring将事务状态以及所有资源和同步绑定到一个特定的订阅。使用Project Reactor的所有反应性代码现在都可以参与反应性事务。必须重写返回标量值并希望访问事务细节的代码,以使用响应类型参与事务。否则,上下文不可用。
Reactor Context is to reactive programming what ThreadLocal is to imperative programming: Contexts allow binding contextual data to a particular execution. For reactive programming, this is a Subscription. Reactor’s Context lets Spring bind the transaction state, along with all resources and synchronizations, to a particular Subscription. All reactive code that uses Project Reactor can now participate in reactive transactions. Code that returns scalar values and that wants to access transactional details must be rewritten to use reactive types to participate in transactions. Otherwise, the Context is not available.

Reactive Transaction Management
反应性事务管理

从Spring Framework 5.2 M2开始,Spring通过ReactiveTransactionManager SPI支持反应性事务管理。
Starting with Spring Framework 5.2 M2, Spring supports reactive transaction management through the ReactiveTransactionManager SPI.

ReactiveTransactionManager是针对使用事务资源的反应性和非阻塞性集成的事务管理抽象。它是反应性@Transactional方法(返回发布者类型)和程序性事务管理(使用TransactionalOperator)的基础。
ReactiveTransactionManager is a transaction management abstraction for reactive and non-blocking integrations that uses transactional resources. It is a foundation for reactive @Transactional methods that return Publisher types and for programmatic transaction management that uses TransactionalOperator.

The first two reactive transaction manager implementations are:

R2DBC through Spring Data R2DBC 1.0 M2
MongoDB through Spring Data MongoDB 2.2 M4
Let’s take a look at how reactive transactions look like:

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(基于方法返回类型)区分应用哪种类型的事务管理:

方法返回发布者类型:反应事务管理
所有其他返回类型:命令式事务管理
Method returns a Publisher type: Reactive Transaction Management
All other return types: Imperative Transaction Management

这种区别非常重要,因为您仍然可以使用诸如JPA或JDBC查询这样的命令式组件。将这些结果包装成发布者类型,可以让Spring应用反应性事务管理,而不是命令性事务管理。也就是说,响应事务安排不会打开JPA或JDBC所需要的线程绑定事务。
JPA查询回来Teacher,那么Mono.just()进行包装,则是反应事务管理

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

这里自己创建了ReactiveTransactionManager
The code above contains some notable components:

R2dbcTransactionManager: This is the reactive transaction manager for a R2DBC ConnectionFactory .
DatabaseClient: The client provides access to SQL databases using R2DBC drivers.
TransactionalOperator: This operator associates all upstream R2DBC publishers with a transactional context. You can use it either operator style as(…::transactional) or call-back style with execute(txStatus -> …).

反应性事务在订阅时以惰性方式启动。操作人员启动一个事务,设置适当的隔离级别,并将数据库连接与其订阅者上下文关联。所有参与的(上游)发布者实例都使用一个上下文绑定的事务连接。
Reactive transactions are started lazily upon subscription. The operator starts a transaction, sets the appropriate isolation level and associates the database connection with its subscriber context. All participating (upstream) Publisher instances use a single Context-bound transactional connection.

Reactive-functional operator chains can be either linear (by using a single Publisher) or non-linear (by merging multiple streams). Reactive transactions affect all upstream Publishers when using operator style. To limit the transaction scope to a particular set of Publishers, apply callback style, as follows:

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

Reactive Transaction Management ships with Spring Framework 5.2 M2, Spring Data MongoDB 2.2 M4, and Spring Data R2DBC 1.0 M2 milestone releases. You can pick up these and start integrating reactive transaction management in your code. We look forward to community feedback so that we can smooth out any sharp edges before shipping release candidates in early June.

comments powered by Disqus


总体看下来就是两种模式
一种还是@Transactional 另一个是自己创建ReactiveTransactionManager

原文地址:https://www.cnblogs.com/ukzq/p/13947158.html