|
4 | 4 | A common pattern when using relational databases is grouping multiple queries within a unit of work that is guarded by a transaction.
|
5 | 5 | Relational databases typically associate a transaction with a single transport connection.
|
6 | 6 | Using different connections hence results in utilizing different transactions.
|
7 |
| -Spring Data R2DBC includes transaction-awareness in `DatabaseClient` that allows you to group multiple statements within the same transaction using https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction[Spring's Transaction Management]. |
| 7 | +Spring Data R2DBC includes transaction-awareness in `DatabaseClient` that allows you to group multiple statements within |
| 8 | +the same transaction using https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction[Spring's Transaction Management]. |
8 | 9 | Spring Data R2DBC provides a implementation for `ReactiveTransactionManager` with `ConnectionFactoryTransactionManager`.
|
9 | 10 | See <<r2dbc.connections.ConnectionFactoryTransactionManager>> for further details.
|
10 | 11 |
|
11 | 12 | .Programmatic Transaction Management
|
12 | 13 | ====
|
13 | 14 | [source,java]
|
14 | 15 | ----
|
15 |
| -ConnectionFactoryTransactionManager tm = new ConnectionFactoryTransactionManager(connectionFactory); |
16 |
| -TransactionalOperator operator = TransactionalOperator.create(tm); |
17 |
| -DatabaseClient db = DatabaseClient.create(connectionFactory); |
| 16 | +ReactiveTransactionManager tm = new ConnectionFactoryTransactionManager(connectionFactory); |
| 17 | +TransactionalOperator operator = TransactionalOperator.create(tm); <1> |
18 | 18 |
|
19 |
| -Mono<Void> atomicOperation = db.execute().sql("INSERT INTO person (id, name, age) VALUES(:id, :name, :age)") |
20 |
| - .bind("id", "joe") |
21 |
| - .bind("name", "Joe") |
22 |
| - .bind("age", 34) |
23 |
| - .fetch().rowsUpdated() |
24 |
| - .then(db.execute().sql("INSERT INTO contacts (id, name) VALUES(:id, :name)") |
25 |
| - .bind("id", "joe") |
26 |
| - .bind("name", "Joe") |
27 |
| - .fetch().rowsUpdated()) |
28 |
| - .then() |
29 |
| - .as(operator::transactional); |
| 19 | +DatabaseClient client = DatabaseClient.create(connectionFactory); |
| 20 | +
|
| 21 | +Mono<Void> atomicOperation = client.execute().sql("INSERT INTO person (id, name, age) VALUES(:id, :name, :age)") |
| 22 | + .bind("id", "joe") |
| 23 | + .bind("name", "Joe") |
| 24 | + .bind("age", 34) |
| 25 | + .fetch().rowsUpdated() |
| 26 | + .then(client.execute().sql("INSERT INTO contacts (id, name) VALUES(:id, :name)") |
| 27 | + .bind("id", "joe") |
| 28 | + .bind("name", "Joe") |
| 29 | + .fetch().rowsUpdated()) |
| 30 | + .then() |
| 31 | + .as(operator::transactional); <2> |
30 | 32 | });
|
31 | 33 | ----
|
| 34 | +<1> Associate the `TransactionalOperator` with the `ReactiveTransactionManager`. |
| 35 | +<2> Bind the operation to the `TransactionalOperator`. |
32 | 36 | ====
|
33 | 37 |
|
34 |
| -https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction-declarative[Spring's declarative Transaction Management] is a less invasive, annotation-based approach to transaction demarcation. |
| 38 | +https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction-declarative[Spring's declarative Transaction Management] |
| 39 | +is a less invasive, annotation-based approach to transaction demarcation. |
35 | 40 |
|
36 | 41 | .Declarative Transaction Management
|
37 | 42 | ====
|
38 | 43 | [source,java]
|
39 | 44 | ----
|
40 |
| -class MyService { |
| 45 | +@Configuration |
| 46 | +@EnableTransactionManagement <1> |
| 47 | +class Config extends AbstractR2dbcConfiguration { |
41 | 48 |
|
42 |
| - private final DatabaseClient db; |
| 49 | + @Override |
| 50 | + public ConnectionFactory connectionFactory() { |
| 51 | + return // ... |
| 52 | + } |
43 | 53 |
|
44 |
| - MyService(DatabaseClient db) { |
45 |
| - this.db = db; |
| 54 | + @Bean |
| 55 | + ReactiveTransactionManager txMgr(ConnectionFactory connectionFactory) { <2> |
| 56 | + return new ConnectionFactoryTransactionManager(connectionFactory); |
46 | 57 | }
|
| 58 | +} |
47 | 59 |
|
| 60 | +@Service |
| 61 | +class MyService { |
| 62 | +
|
| 63 | + private final DatabaseClient client; |
| 64 | +
|
| 65 | + MyService(DatabaseClient client) { |
| 66 | + this.client = client; |
| 67 | + } |
48 | 68 |
|
49 | 69 | @Transactional
|
50 | 70 | public Mono<Void> insertPerson() {
|
51 | 71 |
|
52 |
| - return db.execute().sql("INSERT INTO person (id, name, age) VALUES(:id, :name, :age)") |
| 72 | + return client.execute().sql("INSERT INTO person (id, name, age) VALUES(:id, :name, :age)") |
53 | 73 | .bind("id", "joe")
|
54 | 74 | .bind("name", "Joe")
|
55 | 75 | .bind("age", 34)
|
56 | 76 | .fetch().rowsUpdated()
|
57 |
| - .then(db.execute().sql("INSERT INTO contacts (id, name) VALUES(:id, :name)") |
58 |
| - .bind("id", "joe") |
59 |
| - .bind("name", "Joe") |
60 |
| - .fetch().rowsUpdated()) |
61 |
| - .then(); |
| 77 | + .then(client.execute().sql("INSERT INTO contacts (id, name) VALUES(:id, :name)") |
| 78 | + .bind("id", "joe") |
| 79 | + .bind("name", "Joe") |
| 80 | + .fetch().rowsUpdated()) |
| 81 | + .then(); |
62 | 82 | }
|
63 | 83 | }
|
64 | 84 | ----
|
| 85 | +<1> Enable declarative transaction management. |
| 86 | +<2> Provide a `ReactiveTransactionManager` implementation to back reactive tansaction features. |
65 | 87 | ====
|
0 commit comments