diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoTransactionManager.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoTransactionManager.java
index 1f97bb69e..3f826d9ff 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoTransactionManager.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoTransactionManager.java
@@ -36,16 +36,18 @@ import com.mongodb.client.ClientSession;
/**
* A {@link org.springframework.transaction.PlatformTransactionManager} implementation that manages
- * {@link ClientSession} based transactions for a single {@link MongoDatabaseFactory}.
- * Binds a {@link ClientSession} from the specified {@link MongoDatabaseFactory} to the thread.
+ * {@link ClientSession} based transactions for a single {@link MongoDatabaseFactory}.
+ *
+ * Binds a {@link ClientSession} from the specified {@link MongoDatabaseFactory} to the thread.
* {@link TransactionDefinition#isReadOnly() Readonly} transactions operate on a {@link ClientSession} and enable causal
* consistency, and also {@link ClientSession#startTransaction() start}, {@link ClientSession#commitTransaction()
- * commit} or {@link ClientSession#abortTransaction() abort} a transaction.
+ * commit} or {@link ClientSession#abortTransaction() abort} a transaction.
+ *
* Application code is required to retrieve the {@link com.mongodb.client.MongoDatabase} via
* {@link MongoDatabaseUtils#getDatabase(MongoDatabaseFactory)} instead of a standard
* {@link MongoDatabaseFactory#getMongoDatabase()} call. Spring classes such as
- * {@link org.springframework.data.mongodb.core.MongoTemplate} use this strategy implicitly.
- * By default failure of a {@literal commit} operation raises a {@link TransactionSystemException}. One may override
+ * {@link org.springframework.data.mongodb.core.MongoTemplate} use this strategy implicitly. By default, failure of a
+ * {@literal commit} operation raises a {@link TransactionSystemException}. One may override
* {@link #doCommit(MongoTransactionObject)} to implement the
* Retry Commit Operation
* behavior as outlined in the MongoDB reference manual.
@@ -205,7 +207,7 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
* By default those labels are ignored, nevertheless one might check for
* {@link MongoException#UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL transient commit errors labels} and retry the the
* commit.
- *
+ *
*
*
* int retries = 3;
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoTransactionManager.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoTransactionManager.java
index 4f293c8ed..d1be22a77 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoTransactionManager.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoTransactionManager.java
@@ -37,20 +37,21 @@ import com.mongodb.reactivestreams.client.ClientSession;
/**
* A {@link org.springframework.transaction.ReactiveTransactionManager} implementation that manages
* {@link com.mongodb.reactivestreams.client.ClientSession} based transactions for a single
- * {@link org.springframework.data.mongodb.ReactiveMongoDatabaseFactory}.
+ * {@link org.springframework.data.mongodb.ReactiveMongoDatabaseFactory}.
+ *
* Binds a {@link ClientSession} from the specified
* {@link org.springframework.data.mongodb.ReactiveMongoDatabaseFactory} to the subscriber
- * {@link reactor.util.context.Context}.
- * {@link org.springframework.transaction.TransactionDefinition#isReadOnly() Readonly} transactions operate on a
- * {@link ClientSession} and enable causal consistency, and also {@link ClientSession#startTransaction() start},
+ * {@link reactor.util.context.Context}. {@link org.springframework.transaction.TransactionDefinition#isReadOnly()
+ * Readonly} transactions operate on a {@link ClientSession} and enable causal consistency, and also
+ * {@link ClientSession#startTransaction() start},
* {@link com.mongodb.reactivestreams.client.ClientSession#commitTransaction() commit} or
- * {@link ClientSession#abortTransaction() abort} a transaction.
+ * {@link ClientSession#abortTransaction() abort} a transaction.
+ *
* Application code is required to retrieve the {@link com.mongodb.reactivestreams.client.MongoDatabase} via
* {@link org.springframework.data.mongodb.ReactiveMongoDatabaseUtils#getDatabase(ReactiveMongoDatabaseFactory)} instead
* of a standard {@link org.springframework.data.mongodb.ReactiveMongoDatabaseFactory#getMongoDatabase()} call. Spring
- * classes such as {@link org.springframework.data.mongodb.core.ReactiveMongoTemplate} use this strategy implicitly.
- *
- * By default failure of a {@literal commit} operation raises a {@link TransactionSystemException}. You can override
+ * classes such as {@link org.springframework.data.mongodb.core.ReactiveMongoTemplate} use this strategy implicitly. By
+ * default, failure of a {@literal commit} operation raises a {@link TransactionSystemException}. You can override
* {@link #doCommit(TransactionSynchronizationManager, ReactiveMongoTransactionObject)} to implement the
* Retry Commit Operation
* behavior as outlined in the MongoDB reference manual.
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
index 03c0bb768..a49cd4ae9 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
@@ -48,7 +48,6 @@ import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.convert.EntityReader;
import org.springframework.data.domain.OffsetScrollPosition;
-import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Window;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResult;
@@ -160,6 +159,9 @@ import com.mongodb.client.result.UpdateResult;
*
* You can also set the default {@link #setReadPreference(ReadPreference) ReadPreference} on the template level to
* generally apply a {@link ReadPreference}.
+ *
+ * When using transactions make sure to create this template with the same {@link MongoDatabaseFactory} that is also
+ * used for {@code MongoTransactionManager} creation.
*
* @author Thomas Risberg
* @author Graeme Rocher
@@ -223,6 +225,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
/**
* Constructor used for a basic template configuration.
+ *
+ * If you intend to use transactions, make sure to use {@link #MongoTemplate(MongoDatabaseFactory)} or
+ * {@link #MongoTemplate(MongoDatabaseFactory, MongoConverter)} constructors, otherwise, this template will not
+ * participate in transactions using the default {@code SessionSynchronization.ON_ACTUAL_TRANSACTION} setting as
+ * {@code MongoTransactionManager} uses strictly its configured {@link MongoDatabaseFactory} for transaction
+ * participation.
*
* @param mongoClient must not be {@literal null}.
* @param databaseName must not be {@literal null} or empty.
@@ -641,7 +649,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
/**
* Define if {@link MongoTemplate} should participate in transactions. Default is set to
- * {@link SessionSynchronization#ON_ACTUAL_TRANSACTION}.
+ * {@link SessionSynchronization#ON_ACTUAL_TRANSACTION}.
+ *
* NOTE: MongoDB transactions require at least MongoDB 4.0.
*
* @since 2.1
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java
index 1e24b360f..e1ad78893 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java
@@ -15,7 +15,7 @@
*/
package org.springframework.data.mongodb.core;
-import static org.springframework.data.mongodb.core.query.SerializationUtils.serializeToJsonSafely;
+import static org.springframework.data.mongodb.core.query.SerializationUtils.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -110,18 +110,7 @@ import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes;
-import org.springframework.data.mongodb.core.mapping.event.AfterConvertEvent;
-import org.springframework.data.mongodb.core.mapping.event.AfterDeleteEvent;
-import org.springframework.data.mongodb.core.mapping.event.AfterLoadEvent;
-import org.springframework.data.mongodb.core.mapping.event.AfterSaveEvent;
-import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent;
-import org.springframework.data.mongodb.core.mapping.event.BeforeDeleteEvent;
-import org.springframework.data.mongodb.core.mapping.event.BeforeSaveEvent;
-import org.springframework.data.mongodb.core.mapping.event.MongoMappingEvent;
-import org.springframework.data.mongodb.core.mapping.event.ReactiveAfterConvertCallback;
-import org.springframework.data.mongodb.core.mapping.event.ReactiveAfterSaveCallback;
-import org.springframework.data.mongodb.core.mapping.event.ReactiveBeforeConvertCallback;
-import org.springframework.data.mongodb.core.mapping.event.ReactiveBeforeSaveCallback;
+import org.springframework.data.mongodb.core.mapping.event.*;
import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Collation;
@@ -189,6 +178,9 @@ import com.mongodb.reactivestreams.client.MongoDatabase;
*
* You can also set the default {@link #setReadPreference(ReadPreference) ReadPreference} on the template level to
* generally apply a {@link ReadPreference}.
+ *
+ * When using transactions make sure to create this template with the same {@link ReactiveMongoDatabaseFactory} that is
+ * also used for {@code ReactiveMongoTransactionManager} creation.
*
* @author Mark Paluch
* @author Christoph Strobl
@@ -231,6 +223,12 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
/**
* Constructor used for a basic template configuration.
+ *
+ * If you intend to use transactions, make sure to use {@link #ReactiveMongoTemplate(ReactiveMongoDatabaseFactory)} or
+ * {@link #ReactiveMongoTemplate(ReactiveMongoDatabaseFactory, MongoConverter)} constructors, otherwise, this template
+ * will not participate in transactions using the default {@code SessionSynchronization.ON_ACTUAL_TRANSACTION} setting
+ * as {@code ReactiveMongoTransactionManager} uses strictly its configured {@link ReactiveMongoDatabaseFactory} for
+ * transaction participation.
*
* @param mongoClient must not be {@literal null}.
* @param databaseName must not be {@literal null} or empty.
@@ -573,7 +571,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
/**
* Define if {@link ReactiveMongoTemplate} should participate in transactions. Default is set to
- * {@link SessionSynchronization#ON_ACTUAL_TRANSACTION}.
+ * {@link SessionSynchronization#ON_ACTUAL_TRANSACTION}.
+ *
* NOTE: MongoDB transactions require at least MongoDB 4.0.
*
* @since 2.2
diff --git a/src/main/antora/modules/ROOT/pages/mongodb/client-session-transactions.adoc b/src/main/antora/modules/ROOT/pages/mongodb/client-session-transactions.adoc
index f825690d7..910f2cace 100644
--- a/src/main/antora/modules/ROOT/pages/mongodb/client-session-transactions.adoc
+++ b/src/main/antora/modules/ROOT/pages/mongodb/client-session-transactions.adoc
@@ -294,6 +294,11 @@ static class Config extends AbstractMongoClientConfiguration {
return new MongoTransactionManager(dbFactory);
}
+ @Bean
+ MongoTemplate mongoTemplate(MongoDatabaseFactory dbFactory) { <1>
+ return new MongoTemplate(dbFactory);
+ }
+
// ...
}
@@ -314,6 +319,7 @@ public class StateService {
----
<1> Register `MongoTransactionManager` in the application context.
+Also, make sure to use the same `MongoDatabaseFactory` when creating `MongoTemplate` to participate in transactions in the scope of the same `MongoDatabaseFactory`.
<2> Mark methods as transactional.
NOTE: `@Transactional(readOnly = true)` advises `MongoTransactionManager` to also start a transaction that adds the
@@ -333,6 +339,11 @@ public class Config extends AbstractReactiveMongoConfiguration {
return new ReactiveMongoTransactionManager(factory);
}
+ @Bean
+ ReactiveMongoTemplate reactiveMongoTemplate(ReactiveMongoDatabaseFactory dbFactory) { <1>
+ return new ReactiveMongoTemplate(dbFactory);
+ }
+
// ...
}
@@ -351,6 +362,7 @@ public class StateService {
----
<1> Register `ReactiveMongoTransactionManager` in the application context.
+Also, make sure to use the same `ReactiveMongoDatabaseFactory` when creating `ReactiveMongoTemplate` to participate in transactions in the scope of the same `ReactiveMongoDatabaseFactory`.
<2> Mark methods as transactional.
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
MongoDB does *not* support collection operations, such as collection creation, within a transaction.
This also affects the on the fly collection creation that happens on first usage.
-Therefore make sure to have all required structures in place.
+Therefore, make sure to have all required structures in place.
*Transient Errors*
MongoDB can add special labels to errors raised during transactional operations.
Those may indicate transient failures that might vanish by merely retrying the operation.
We highly recommend https://github.com/spring-projects/spring-retry[Spring Retry] for those purposes.
-Nevertheless one may override `MongoTransactionManager#doCommit(MongoTransactionObject)` to implement a https://docs.mongodb.com/manual/core/transactions/#retry-commit-operation[Retry Commit Operation]
+Nevertheless, one may override `MongoTransactionManager#doCommit(MongoTransactionObject)` to implement a https://docs.mongodb.com/manual/core/transactions/#retry-commit-operation[Retry Commit Operation]
behavior as outlined in the MongoDB reference manual.
*Count*
MongoDB `count` operates upon collection statistics which may not reflect the actual situation within a transaction.
-The server responds with _error 50851_ when issuing a `count` command inside of a multi-document transaction.
+The server responds with _error 50851_ when issuing a `count` command inside a multi-document transaction.
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`.
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:
session.startTransaction();
template.withSession(session)
- .execute(action -> {
- action.count(query(where("state").is("active")), Step.class)
- ...
+ .execute(ops -> {
+ return ops.count(query(where("state").is("active")), Step.class)
+ });
----
====