Preface
Enabling and using MongoDB transactions in Spring Boot mainly depends on the following aspects:
Server and deployment mode:
- MongoDB version 4.0 or later supports multi-document ACID transactions on replica sets (Replica Set).
- MongoDB version 4.2 or later supports multi-document ACID transactions on Sharded Cluster.
- Standalone (single-node) mode does not support multi-document transactions. A MongoDB instance must be part of a replica set or shard cluster.
Boot and Spring Data MongoDB versions:
- Make sure that the version of Spring Boot used (and the version of Spring Data MongoDB it manages) supports MongoDB transactions. Newer Spring Boot versions (2. and later) provide good support.
- The spring-boot-starter-data-mongodb dependency is required.
3. Configure MongoTransactionManager:
Spring Boot automatically configures MongoTransactionManager when an appropriate condition is detected (for example, the connection URI points to a replica set).
4. Use @Transactional annotation:
This is the standard way to manage transactions in Spring.
Here is how to enable and use MongoDB transactions in Spring Boot:
Step 1: Ensure that the MongoDB environment supports transactions
Confirm the MongoDB server version (4.0+ for replica sets, 4.2+ for sharded clusters).
Confirm that MongoDB is running in replica set or sharded cluster mode.
Step 2: Add dependencies
In your (Maven) or (Gradle) file, make sure you have a starter for Spring Data MongoDB:
Maven ():
<dependency> <groupId></groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency>
Step 3: Configure the database connection URI
Configure the MongoDB connection URI in or . The key is to include the replicaSet parameter (if your MongoDB is a replica set).
:
=mongodb://localhost:27017,localhost:27018,localhost:27019/mydatabase?replicaSet=rs0 # Or for sharded clusters, connect to the mongos instance# =mongodb://mongos1:27017,mongos2:27017/mydatabase
localhost:27017,localhost:27018,localhost:27019: Replica set member address.
mydatabase: database name.
replicaSet=rs0: Replicaset name. This parameter is very important for Spring Boot to automatically configure MongoTransactionManager.
Step 4: Enable Transaction Manager
a) Automatic configuration (recommended)
If the replicaSet parameter is correctly configured (or the mongos connected to the sharded cluster), Spring Boot will usually automatically configure a MongoTransactionManager bean for you. No additional configuration is required.
b) Manual configuration (if the automatic configuration does not take effect or requires customization)
If you need to configure manually, you can create a MongoTransactionManager bean in the configuration class:
import ; import ; import ; import ; import ; import ; // For example only, non-essential @Configuration public class MongoConfig { // Spring Boot will automatically configure MongoDatabaseFactory // You just need to inject it to create MongoTransactionManager @Bean MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) { return new MongoTransactionManager(dbFactory); } // Optional: If you also want to configure a MongoTemplate bean // @Bean // public MongoTemplate mongoTemplate(MongoDatabaseFactory dbFactory, MongoClient mongoClient) { // return new MongoTemplate(mongoClient, ().getName()); // } }
Note: Normally, if your URI is configured correctly, Spring Boot's automatic configuration is sufficient, and you don't need to create this bean manually.
Step 5: Use @Transactional in the Service Layer
The @Transactional annotation of Spring can now be used on the Service method to declare transactions.
import ; import ; import ; // Spring's transaction annotationimport ; // More general MongoDB exceptionimport ; // Transaction specific exception @Service public class AccountService { @Autowired private AccountRepository accountRepository; // Suppose you have an AccountRepository @Autowired private AuditLogRepository auditLogRepository; // Suppose you have an AuditLogRepository /** * Example: Transfer money in a transaction and log logs * If any step fails, the entire operation will roll back */ @Transactional // Key notes public void transferMoney(String fromAccountId, String toAccountId, double amount) { try { Account fromAccount = (fromAccountId) .orElseThrow(() -> new RuntimeException("Source account not found")); Account toAccount = (toAccountId) .orElseThrow(() -> new RuntimeException("Destination account not found")); if (() < amount) { throw new RuntimeException("Insufficient funds"); } (() - amount); (() + amount); (fromAccount); // Simulate a possible error to test rollback // if (true) { // throw new RuntimeException("Simulated error during transfer!"); // } (toAccount); // Record audit logs AuditLog log = new AuditLog("Transfer of " + amount + " from " + fromAccountId + " to " + toAccountId); (log); ("Transfer successful and logged!"); } catch (RuntimeException e) { // @Transactional will automatically roll back when the RuntimeException is thrown // You can log errors here, but you don't need to rollback manually ("Transfer failed: " + ()); throw e; // Rethrow so that Spring can capture and roll back transactions } } /** * Example: Read-only transaction * For operations that only need to read data, it can be marked as read-only, which may have some performance optimizations. */ @Transactional(readOnly = true) public Account getAccountDetails(String accountId) { return (accountId).orElse(null); } // Assumptions of entities and repositories // , // extends MongoRepository<Account, String> // extends MongoRepository<AuditLog, String> }
How it works:
- When a method annotated by @Transactional is called, Spring starts a MongoDB transaction (through MongoTransactionManager).
- All database operations within a method (for example ()) are executed in the context of this transaction.
- If the method completes successfully (no uncaught RuntimeException or Error is thrown), the transaction will be committed.
- If the method throws any uncaught RuntimeException or Error (default behavior), the transaction will be rolled back. Checked Exceptions will not trigger rollbacks by default unless specifically specified via @Transactional(rollbackFor = ).
Step 6: Exception handling and retry (Important!)
MongoDB transactions may be aborted due to write conflicts. This happens when two concurrent transactions try to modify the same document. MongoDB aborts one of the transactions and throws a MongoTransactionException (usually its subclass, such as MongoWriteConflictException).
These exceptions must be caught in the application and the entire transaction is retryed.
// On the caller or a higher level service@Service public class TransactionalCallerService { @Autowired private AccountService accountService; private static final int MAX_RETRIES = 3; public void performTransferWithRetry(String from, String to, double amount) { int retries = 0; boolean success = false; while (retries < MAX_RETRIES && !success) { try { (from, to, amount); success = true; // If there is no exception, the marking will be successful } catch (MongoTransactionException e) { //Catch transaction-related exceptions, especially write conflicts retries++; ("Transaction failed due to conflict, retrying (" + retries + "/" + MAX_RETRIES + "): " + ()); if (retries >= MAX_RETRIES) { ("Max retries reached. Transfer aborted."); throw e; // Or throw a custom business exception } // Consider adding a short delay here try { (100 * retries); // Simple exponential backoff } catch (InterruptedException ie) { ().interrupt(); throw new RuntimeException("Retry interrupted", ie); } } catch (RuntimeException e) { //Catch other business logic exceptions ("Transfer failed due to business error: " + ()); throw e; // These usually don't need to be tried again } } } }
Summary of key points:
- MongoDB environment: Make sure to be a replica set (4.0+) or sharded cluster (4.2+).
- URI configuration: Set the replicaSet parameter correctly in .
- MongoTransactionManager: Usually automatically configured by Spring Boot.
- @Transactional: Used on Service methods.
- Exception handling: MongoTransactionException must be handled and retry logic is implemented to deal with write conflicts.
- Transaction scope: Try to keep transactions short and avoid long-running transactions.
- Non-transactional operations: Some MongoDB operations (such as creating collections, creating indexes) are not executed within a transaction or have specific behavior within a transaction.
Through these steps, we can effectively use MongoDB's multi-document ACID transactions in our Spring Boot application.
This is the end of this article about a brief analysis of how to enable MongoDB transactions in SpringBoot. For more related content on enabling MongoDB transactions in SpringBoot, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!