Skip to content

Commit d147b1f

Browse files
committed
Document how to create MongoTemplate and MongoTransactionManager for default transaction participation.
Refine documentation and indicate relationship to MongoDatabaseFactory. Closes #5019
1 parent c9495c8 commit d147b1f

File tree

5 files changed

+54
-22
lines changed

5 files changed

+54
-22
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoTransactionManager.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,17 @@
3737
/**
3838
* A {@link org.springframework.transaction.PlatformTransactionManager} implementation that manages
3939
* {@link ClientSession} based transactions for a single {@link MongoDatabaseFactory}.
40-
* <br />
40+
* <p>
4141
* Binds a {@link ClientSession} from the specified {@link MongoDatabaseFactory} to the thread.
42-
* <br />
4342
* {@link TransactionDefinition#isReadOnly() Readonly} transactions operate on a {@link ClientSession} and enable causal
4443
* consistency, and also {@link ClientSession#startTransaction() start}, {@link ClientSession#commitTransaction()
4544
* commit} or {@link ClientSession#abortTransaction() abort} a transaction.
46-
* <br />
45+
* <p>
4746
* Application code is required to retrieve the {@link com.mongodb.client.MongoDatabase} via
4847
* {@link MongoDatabaseUtils#getDatabase(MongoDatabaseFactory)} instead of a standard
4948
* {@link MongoDatabaseFactory#getMongoDatabase()} call. Spring classes such as
50-
* {@link org.springframework.data.mongodb.core.MongoTemplate} use this strategy implicitly.
51-
* <br />
52-
* By default failure of a {@literal commit} operation raises a {@link TransactionSystemException}. One may override
49+
* {@link org.springframework.data.mongodb.core.MongoTemplate} use this strategy implicitly. By default, failure of a
50+
* {@literal commit} operation raises a {@link TransactionSystemException}. One may override
5351
* {@link #doCommit(MongoTransactionObject)} to implement the
5452
* <a href="https://docs.mongodb.com/manual/core/transactions/#retry-commit-operation">Retry Commit Operation</a>
5553
* behavior as outlined in the MongoDB reference manual.
@@ -206,6 +204,7 @@ protected final void doCommit(DefaultTransactionStatus status) throws Transactio
206204
* By default those labels are ignored, nevertheless one might check for
207205
* {@link MongoException#UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL transient commit errors labels} and retry the the
208206
* commit. <br />
207+
*
209208
* <pre>
210209
* <code>
211210
* int retries = 3;

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoTransactionManager.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,20 +37,21 @@
3737
/**
3838
* A {@link org.springframework.transaction.ReactiveTransactionManager} implementation that manages
3939
* {@link com.mongodb.reactivestreams.client.ClientSession} based transactions for a single
40-
* {@link org.springframework.data.mongodb.ReactiveMongoDatabaseFactory}. <br />
40+
* {@link org.springframework.data.mongodb.ReactiveMongoDatabaseFactory}.
41+
* <p>
4142
* Binds a {@link ClientSession} from the specified
4243
* {@link org.springframework.data.mongodb.ReactiveMongoDatabaseFactory} to the subscriber
43-
* {@link reactor.util.context.Context}. <br />
44-
* {@link org.springframework.transaction.TransactionDefinition#isReadOnly() Readonly} transactions operate on a
45-
* {@link ClientSession} and enable causal consistency, and also {@link ClientSession#startTransaction() start},
44+
* {@link reactor.util.context.Context}. {@link org.springframework.transaction.TransactionDefinition#isReadOnly()
45+
* Readonly} transactions operate on a {@link ClientSession} and enable causal consistency, and also
46+
* {@link ClientSession#startTransaction() start},
4647
* {@link com.mongodb.reactivestreams.client.ClientSession#commitTransaction() commit} or
47-
* {@link ClientSession#abortTransaction() abort} a transaction. <br />
48+
* {@link ClientSession#abortTransaction() abort} a transaction.
49+
* <p>
4850
* Application code is required to retrieve the {@link com.mongodb.reactivestreams.client.MongoDatabase} via
4951
* {@link org.springframework.data.mongodb.ReactiveMongoDatabaseUtils#getDatabase(ReactiveMongoDatabaseFactory)} instead
5052
* of a standard {@link org.springframework.data.mongodb.ReactiveMongoDatabaseFactory#getMongoDatabase()} call. Spring
51-
* classes such as {@link org.springframework.data.mongodb.core.ReactiveMongoTemplate} use this strategy implicitly.
52-
* <br />
53-
* By default failure of a {@literal commit} operation raises a {@link TransactionSystemException}. You can override
53+
* classes such as {@link org.springframework.data.mongodb.core.ReactiveMongoTemplate} use this strategy implicitly. By
54+
* default, failure of a {@literal commit} operation raises a {@link TransactionSystemException}. You can override
5455
* {@link #doCommit(TransactionSynchronizationManager, ReactiveMongoTransactionObject)} to implement the
5556
* <a href="https://docs.mongodb.com/manual/core/transactions/#retry-commit-operation">Retry Commit Operation</a>
5657
* behavior as outlined in the MongoDB reference manual.

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@
156156
* <p>
157157
* You can also set the default {@link #setReadPreference(ReadPreference) ReadPreference} on the template level to
158158
* generally apply a {@link ReadPreference}.
159+
* <p>
160+
* When using transactions make sure to create this template with the same {@link MongoDatabaseFactory} that is also
161+
* used for {@code MongoTransactionManager} creation.
159162
*
160163
* @author Thomas Risberg
161164
* @author Graeme Rocher
@@ -219,6 +222,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
219222

220223
/**
221224
* Constructor used for a basic template configuration.
225+
* <p>
226+
* If you intend to use transactions, make sure to use {@link #MongoTemplate(MongoDatabaseFactory)} or
227+
* {@link #MongoTemplate(MongoDatabaseFactory, MongoConverter)} constructors, otherwise, this template will not
228+
* participate in transactions using the default {@code SessionSynchronization.ON_ACTUAL_TRANSACTION} setting as
229+
* {@code MongoTransactionManager} uses strictly its configured {@link MongoDatabaseFactory} for transaction
230+
* participation.
222231
*
223232
* @param mongoClient must not be {@literal null}.
224233
* @param databaseName must not be {@literal null} or empty.
@@ -628,7 +637,8 @@ public MongoTemplate withSession(ClientSession session) {
628637

629638
/**
630639
* Define if {@link MongoTemplate} should participate in transactions. Default is set to
631-
* {@link SessionSynchronization#ON_ACTUAL_TRANSACTION}.<br />
640+
* {@link SessionSynchronization#ON_ACTUAL_TRANSACTION}.
641+
* <p>
632642
* <strong>NOTE:</strong> MongoDB transactions require at least MongoDB 4.0.
633643
*
634644
* @since 2.1

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,9 @@
177177
* <p>
178178
* You can also set the default {@link #setReadPreference(ReadPreference) ReadPreference} on the template level to
179179
* generally apply a {@link ReadPreference}.
180+
* <p>
181+
* When using transactions make sure to create this template with the same {@link ReactiveMongoDatabaseFactory} that is
182+
* also used for {@code ReactiveMongoTransactionManager} creation.
180183
*
181184
* @author Mark Paluch
182185
* @author Christoph Strobl
@@ -219,6 +222,12 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
219222

220223
/**
221224
* Constructor used for a basic template configuration.
225+
* <p>
226+
* If you intend to use transactions, make sure to use {@link #ReactiveMongoTemplate(ReactiveMongoDatabaseFactory)} or
227+
* {@link #ReactiveMongoTemplate(ReactiveMongoDatabaseFactory, MongoConverter)} constructors, otherwise, this template
228+
* will not participate in transactions using the default {@code SessionSynchronization.ON_ACTUAL_TRANSACTION} setting
229+
* as {@code ReactiveMongoTransactionManager} uses strictly its configured {@link ReactiveMongoDatabaseFactory} for
230+
* transaction participation.
222231
*
223232
* @param mongoClient must not be {@literal null}.
224233
* @param databaseName must not be {@literal null} or empty.
@@ -560,7 +569,8 @@ public <T> Flux<T> execute(ReactiveSessionCallback<T> action, Consumer<ClientSes
560569

561570
/**
562571
* Define if {@link ReactiveMongoTemplate} should participate in transactions. Default is set to
563-
* {@link SessionSynchronization#ON_ACTUAL_TRANSACTION}.<br />
572+
* {@link SessionSynchronization#ON_ACTUAL_TRANSACTION}.
573+
* <p>
564574
* <strong>NOTE:</strong> MongoDB transactions require at least MongoDB 4.0.
565575
*
566576
* @since 2.2

src/main/antora/modules/ROOT/pages/mongodb/client-session-transactions.adoc

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,11 @@ static class Config extends AbstractMongoClientConfiguration {
294294
return new MongoTransactionManager(dbFactory);
295295
}
296296
297+
@Bean
298+
MongoTemplate mongoTemplate(MongoDatabaseFactory dbFactory) { <1>
299+
return new MongoTemplate(dbFactory);
300+
}
301+
297302
// ...
298303
}
299304
@@ -314,6 +319,7 @@ public class StateService {
314319
----
315320

316321
<1> Register `MongoTransactionManager` in the application context.
322+
Also, make sure to use the same `MongoDatabaseFactory` when creating `MongoTemplate` to participate in transactions in the scope of the same `MongoDatabaseFactory`.
317323
<2> Mark methods as transactional.
318324

319325
NOTE: `@Transactional(readOnly = true)` advises `MongoTransactionManager` to also start a transaction that adds the
@@ -333,6 +339,11 @@ public class Config extends AbstractReactiveMongoConfiguration {
333339
return new ReactiveMongoTransactionManager(factory);
334340
}
335341
342+
@Bean
343+
ReactiveMongoTemplate reactiveMongoTemplate(ReactiveMongoDatabaseFactory dbFactory) { <1>
344+
return new ReactiveMongoTemplate(dbFactory);
345+
}
346+
336347
// ...
337348
}
338349
@@ -351,6 +362,7 @@ public class StateService {
351362
----
352363

353364
<1> Register `ReactiveMongoTransactionManager` in the application context.
365+
Also, make sure to use the same `ReactiveMongoDatabaseFactory` when creating `ReactiveMongoTemplate` to participate in transactions in the scope of the same `ReactiveMongoDatabaseFactory`.
354366
<2> Mark methods as transactional.
355367

356368
NOTE: `@Transactional(readOnly = true)` advises `ReactiveMongoTransactionManager` to also start a transaction that adds the `ClientSession` to outgoing requests.
@@ -418,20 +430,20 @@ Please refer to https://docs.mongodb.com/manual/reference/connection-string/#con
418430

419431
MongoDB does *not* support collection operations, such as collection creation, within a transaction.
420432
This also affects the on the fly collection creation that happens on first usage.
421-
Therefore make sure to have all required structures in place.
433+
Therefore, make sure to have all required structures in place.
422434

423435
*Transient Errors*
424436

425437
MongoDB can add special labels to errors raised during transactional operations.
426438
Those may indicate transient failures that might vanish by merely retrying the operation.
427439
We highly recommend https://github.com/spring-projects/spring-retry[Spring Retry] for those purposes.
428-
Nevertheless one may override `MongoTransactionManager#doCommit(MongoTransactionObject)` to implement a https://docs.mongodb.com/manual/core/transactions/#retry-commit-operation[Retry Commit Operation]
440+
Nevertheless, one may override `MongoTransactionManager#doCommit(MongoTransactionObject)` to implement a https://docs.mongodb.com/manual/core/transactions/#retry-commit-operation[Retry Commit Operation]
429441
behavior as outlined in the MongoDB reference manual.
430442

431443
*Count*
432444

433445
MongoDB `count` operates upon collection statistics which may not reflect the actual situation within a transaction.
434-
The server responds with _error 50851_ when issuing a `count` command inside of a multi-document transaction.
446+
The server responds with _error 50851_ when issuing a `count` command inside a multi-document transaction.
435447
Once `MongoTemplate` detects an active transaction, all exposed `count()` methods are converted and delegated to the aggregation framework using `$match` and `$count` operators, preserving `Query` settings, such as `collation`.
436448

437449
Restrictions apply when using geo commands inside of the aggregation count helper.
@@ -453,9 +465,9 @@ The following snippet shows `count` usage inside the session-bound closure:
453465
session.startTransaction();
454466
455467
template.withSession(session)
456-
.execute(action -> {
457-
action.count(query(where("state").is("active")), Step.class)
458-
...
468+
.execute(ops -> {
469+
return ops.count(query(where("state").is("active")), Step.class)
470+
});
459471
----
460472
====
461473

0 commit comments

Comments
 (0)