如何配置Flapdoodle Embedded MongoDB使其支持事务?
解决Flapdoodle Embedded MongoDB支持事务的配置方案
核心原因
MongoDB事务仅支持副本集/分片集群部署模式,单节点嵌入式MongoDB默认不支持事务和重试写操作,这是报错的根本原因。
解决方案步骤
1. 配置嵌入式MongoDB以副本集模式启动
修改配置类,确保启用副本集并正确配置MongoClient连接参数:
@Configuration public class EmbeddedMongoTransactionConfig extends AbstractMongoClientConfiguration { @Value("${spring.data.mongodb.database}") private String database; private static final String REPLICA_SET_NAME = "rs0"; @Bean public MongoTransactionManager mongoTransactionManager(MongoDatabaseFactory dbFactory) { return new MongoTransactionManager(dbFactory); } @Bean public MongodArguments mongodArguments() { return MongodArguments.builder() // 启用副本集,指定磁盘存储路径和大小,设置副本集名称 .replication(Storage.of(new File("target/embedded-mongodb"), 10)) .replicaSetName(REPLICA_SET_NAME) .build(); } @Override protected String getDatabaseName() { return database; } @Override public MongoClient mongoClient() { // 构建指向副本集的连接字符串,启用重试写 ConnectionString connectionString = new ConnectionString( String.format("mongodb://localhost:%d/%s?replicaSet=%s&retryWrites=true", mongodProcess().getConfig().net().port(), database, REPLICA_SET_NAME) ); return MongoClients.create(MongoClientSettings.builder() .applyConnectionString(connectionString) .build()); } @Bean(destroyMethod = "stop") public MongodProcess mongodProcess(MongodExecutable mongodExecutable) throws IOException { return mongodExecutable.start(); } @Bean public MongodExecutable mongodExecutable(MongodStarter mongodStarter, MongodConfig mongodConfig) { return mongodStarter.prepare(mongodConfig); } @Bean public MongodConfig mongodConfig(MongodArguments mongodArguments) { return MongodConfig.builder() .version(Version.of("5.0.5")) // 匹配指定的MongoDB版本 .net(new Net(27017, Network.localhostIsIPv6())) .mongodArguments(mongodArguments) .build(); } @Bean public MongodStarter mongodStarter() { return MongodStarter.getDefaultInstance(); } }
2. 修正application.properties配置
添加MongoDB连接相关配置,明确指向副本集:
# 嵌入式MongoDB版本 de.flapdoodle.mongodb.embedded.version=5.0.5 # 数据库名称 spring.data.mongodb.database=testdb # 副本集连接字符串(也可通过配置类构建,此处作为备选) spring.data.mongodb.uri=mongodb://localhost:27017/testdb?replicaSet=rs0&retryWrites=true
3. 统一依赖版本兼容性
SpringBoot 2.7.8需确保Flapdoodle依赖版本一致,避免版本冲突:
<dependency> <groupId>de.flapdoodle.embed</groupId> <artifactId>de.flapdoodle.embed.mongo</artifactId> <version>4.6.1</version> <scope>test</scope> </dependency> <dependency> <groupId>de.flapdoodle.embed</groupId> <artifactId>de.flapdoodle.embed.mongo.spring27x</artifactId> <version>4.6.1</version> <scope>test</scope> </dependency>
4. 验证事务功能
在测试类中编写事务验证用例:
@SpringBootTest @Transactional class MongoTransactionTest { @Autowired private MongoTemplate mongoTemplate; @Test void testTransactionRollback() { // 插入第一条数据 mongoTemplate.insert(new TestUser("test-user-1")); // 模拟异常触发回滚 if (true) { throw new RuntimeException("Trigger transaction rollback"); } // 插入第二条数据(不会执行) mongoTemplate.insert(new TestUser("test-user-2")); // 验证数据是否全部回滚 long userCount = mongoTemplate.count(Query.query(Criteria.where("username").is("test-user-1")), TestUser.class); Assertions.assertEquals(0, userCount); } @Data @NoArgsConstructor @AllArgsConstructor static class TestUser { private String username; } }
关键注意事项
- 副本集模式必须使用磁盘存储(不能用内存模式),否则无法维持副本集状态。
- 连接字符串必须指定
replicaSet参数,否则MongoClient不会识别为副本集部署。 - 测试类或方法需添加
@Transactional注解,Spring才会自动管理MongoDB事务。
内容的提问来源于stack exchange,提问作者GHASSEN
相关产品推荐
相关产品推荐

