1. 概述
从 MongoDB 4.0 开始,官方正式支持多文档 ACID 事务。与此同时,Spring Data 的 Lovelace 版本(即 Spring Data MongoDB 2.x)也提供了对 MongoDB 原生事务的支持。
在本篇文章中,我们将深入探讨 Spring Data MongoDB 对同步和响应式事务的支持,并介绍如何使用 Spring 的 TransactionTemplate 来实现非原生事务。
如果你对 Spring Data MongoDB 还不熟悉,可以先参考我们的 Spring Data MongoDB 入门指南。
2. 配置 MongoDB 4.0 环境
要体验 MongoDB 的事务功能,首先需要安装并运行 MongoDB 4.0 或以上版本。
你可以从 MongoDB 官方下载中心 获取最新版本。
启动 MongoDB 时,需要以副本集模式运行:
mongod --replSet rs0
然后初始化副本集(如果尚未初始化):
mongo --eval "rs.initiate()"
⚠️ 注意:目前 MongoDB 的事务功能仅支持副本集模式,单节点模式不支持。
3. Maven 依赖配置
要在项目中使用 Spring Data MongoDB 的事务功能,需要添加以下依赖:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
<version>2.7.11</version>
</dependency>
你可以在 Maven 中央仓库 查找最新版本。
4. MongoDB 配置类
配置 MongoDB 事务支持的关键在于注册 MongoTransactionManager:
@Configuration
@EnableMongoRepositories(basePackages = "com.baeldung.repository")
public class MongoConfig extends AbstractMongoClientConfiguration{
@Bean
MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) {
return new MongoTransactionManager(dbFactory);
}
@Override
protected String getDatabaseName() {
return "test";
}
@Override
public MongoClient mongoClient() {
final ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017/test");
final MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
.applyConnectionString(connectionString)
.build();
return MongoClients.create(mongoClientSettings);
}
}
✅ 要点:必须显式注册 MongoTransactionManager,否则事务功能不会生效(默认是关闭的)。
5. 同步事务支持
配置完成后,使用事务就非常简单了:只需在方法上添加 @Transactional 注解,方法体内的所有操作就会被包裹在一个事务中执行。
@Test
@Transactional
public void whenPerformMongoTransaction_thenSuccess() {
userRepository.save(new User("John", 30));
userRepository.save(new User("Ringo", 35));
Query query = new Query().addCriteria(Criteria.where("name").is("John"));
List<User> users = mongoTemplate.find(query, User.class);
assertThat(users.size(), is(1));
}
⚠️ 注意:某些命令在事务中是不被支持的,例如 listCollections
。以下代码会抛出 MongoTransactionException:
@Test(expected = MongoTransactionException.class)
@Transactional
public void whenListCollectionDuringMongoTransaction_thenException() {
if (mongoTemplate.collectionExists(User.class)) {
mongoTemplate.save(new User("John", 30));
mongoTemplate.save(new User("Ringo", 35));
}
}
6. TransactionTemplate 非原生事务
除了使用注解方式,Spring Data 也支持通过 TransactionTemplate 实现非原生事务控制。
这种方式更灵活,适合手动控制事务边界:
@Test
public void givenTransactionTemplate_whenPerformTransaction_thenSuccess() {
mongoTemplate.setSessionSynchronization(SessionSynchronization.ALWAYS);
TransactionTemplate transactionTemplate = new TransactionTemplate(mongoTransactionManager);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
mongoTemplate.insert(new User("Kim", 20));
mongoTemplate.insert(new User("Jack", 45));
};
});
Query query = new Query().addCriteria(Criteria.where("name").is("Jack"));
List<User> users = mongoTemplate.find(query, User.class);
assertThat(users.size(), is(1));
}
✅ 关键点:使用 TransactionTemplate 时,必须将 SessionSynchronization 设置为 ALWAYS。
7. 响应式事务支持
Spring Data MongoDB 同样支持响应式编程模型下的事务操作。
首先,添加响应式 MongoDB 的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
<version>2.7.11</version>
</dependency>
以及响应式测试依赖:
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<version>3.5.4</version>
<scope>test</scope>
</dependency>
响应式 MongoDB 的配置如下:
@Configuration
@EnableReactiveMongoRepositories(basePackages = "com.baeldung.reactive.repository")
public class MongoReactiveConfig extends AbstractReactiveMongoConfiguration {
@Override
public MongoClient reactiveMongoClient() {
return MongoClients.create();
}
@Override
protected String getDatabaseName() {
return "reactive";
}
@Bean
public TransactionalOperator transactionalOperator(
ReactiveTransactionManager reactiveTransactionManager) {
return TransactionalOperator.create(reactiveTransactionManager);
}
}
在响应式流中使用事务的方式如下:
@Autowired
private TransactionalOperator transactionalOperator;
@Autowired
private ReactiveMongoTemplate mongoTemplate;
@Test
public void whenPerformTransaction_thenSuccess() {
User user1 = new User("Jane", 23);
User user2 = new User("John", 34);
Mono<User> saveEntity1 = mongoTemplate.save(user1);
Mono<User> saveEntity2 = mongoTemplate.save(user2);
saveEntity1.then(saveEntity2).then().as(transactionalOperator::transactional);
}
更多响应式 MongoDB 的内容,可以参考我们的 响应式 MongoDB 教程。
8. 总结
本文我们介绍了如何在 Spring Data MongoDB 中使用:
- 原生事务(通过
@Transactional
) - 非原生事务(通过
TransactionTemplate
) - 响应式事务(通过
TransactionalOperator
)
完整代码示例可以在 GitHub 项目 中获取。