MongoDB transactions with Spring Boot 3
Transactions won’t work without next things:
- replica set
Since transactions are built on concepts of logical sessions they require mechanics (like oplog) which are only available in replica set environment.
You can always convert a standalone to a single noded replica set and transactions will work with this one node.
https://docs.mongodb.com/manual/tutorial/convert-standalone-to-replica-set/
- MongoTransactionManager
Unless you specify a
MongoTransactionManager
within your application context, transaction support is DISABLED. You can usesetSessionSynchronization(ALWAYS)
to participate in ongoing non-native MongoDB transactions.
That’s main reason why newly created Spring Boot project with MongoDB will fail with next error:
1
java.lang.IllegalStateException: Failed to retrieve PlatformTransactionManager for @Transactional test:
What to do:
- Create replica set
- Configure
MongoTransactionManager
asPlatformTransactionManager
- Update application properties
- Fix DataMongoTest tests
Create replica set
Choose preferred way to create replica set:
- Docker single node replica set
- Docker multiple node replica set
- Docker compose single node replica set
Configure PlatformTransactionManager
Register MongoTransactionManager
in the application context.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.MongoTransactionManager;
import org.springframework.data.mongodb.config.AbstractMongoClientConfiguration;
@Configuration
public class MongoClientConfiguration extends AbstractMongoClientConfiguration {
@Value("${spring.data.mongodb.database}")
private String databaseName;
@Bean
public MongoTransactionManager transactionManager(MongoDatabaseFactory mongoDatabaseFactory) {
return new MongoTransactionManager(mongoDatabaseFactory);
}
@NotNull
@Override
protected String getDatabaseName() {
return databaseName;
}
}
Update application properties
1
spring.data.mongodb.replica-set-name=myReplicaSet
Fix DataMongoTest tests
Looks like @DataMongoTest
still not activates autoconfiguration for MongoDB transactions.
References:
Proposal to import TransactionAutoConfiguration
didn’t help me
1
@ImportAutoConfiguration(TransactionAutoConfiguration.class)
So I decided to replace it with MongoDBConfig import
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import app.config.MongoDBConfig;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import org.springframework.context.annotation.Import;
import org.springframework.transaction.annotation.Transactional;
@DataMongoTest
@Transactional
@Import(MongoDBConfig.class)
public class MongoTest {
@Test
public void testTransaction() {
}
}