Spring Data MongoDB事务

2023/05/18

1. 概述

从4.0版本开始,MongoDB支持多文档ACID事务。而且,Spring Data Lovelace现在提供对这些原生MongoDB事务的支持

在本教程中,我们将讨论Spring Data MongoDB对同步和响应式事务的支持。

我们还将查看用于非原生事务支持的Spring Data TransactionTemplate。

有关此Spring Data模块的介绍,请查看我们的介绍性文章

2. 安装MongoDB 4.0

首先,我们需要设置最新的MongoDB来尝试新的原生事务支持。

首先,我们必须从MongoDB下载中心下载最新版本。

接下来,我们将使用命令行启动mongod服务:

mongod --replSet rs0

最后,启动副本集-如果尚未启动:

mongo --eval "rs.initiate()"

请注意,MongoDB目前支持副本集上的事务。

3. Maven配置

接下来,我们需要将以下依赖项添加到我们的pom.xml中:

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-mongodb</artifactId>
    <version>3.0.3.RELEASE</version>
</dependency>

可以在中央仓库上找到该库的最新版本。

4. MongoDB配置

现在,让我们来看看我们的配置:

@Configuration
@EnableMongoRepositories(basePackages = "cn.tuyucheng.taketoday.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以启用原生MongoDB事务,因为它们默认情况下是禁用的。

5. 同步事务

完成配置后,我们需要做的就是使用原生MongoDB事务-使用@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命令-例如:

@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));
    }
}

此示例在我们使用collectionExists()方法时抛出MongoTransactionException。

6. TransactionTemplate

我们看到了Spring Data如何支持新的MongoDB原生事务。此外,Spring Data还提供了非原生选项。

我们可以使用Spring DataTransactionTemplate执行非原生事务

@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));
}

我们需要将SessionSynchronization设置为ALWAYS以使用非原生Spring Data事务。

7. 响应式事务

最后,我们将看一下Spring Data对MongoDB响应式事务的支持

我们需要向pom.xml添加更多依赖项以使用响应式MongoDB:

<dependency>
    <groupId>org.mongodb</groupId>
    <artifactId>mongodb-driver-reactivestreams</artifactId>
    <version>4.1.0</version>
</dependency>
<dependency>
    <groupId>org.mongodb</groupId>
    <artifactId>mongodb-driver-sync</artifactId>
    <version>4.0.5</version>
</dependency>
<dependency>
    <groupId>io.projectreactor</groupId>
    <artifactId>reactor-test</artifactId>
    <version>3.2.0.RELEASE</version>
    <scope>test</scope>
</dependency>

Maven Central上提供了mongodb-driver-reactivestreamsmongodb-driver-syncreactor-test依赖项。

当然,我们需要配置响应式MongoDB:

@Configuration
@EnableReactiveMongoRepositories(basePackages = "cn.tuyucheng.taketoday.reactive.repository")
public class MongoReactiveConfig
      extends AbstractReactiveMongoConfiguration {

    @Override
    public MongoClient reactiveMongoClient() {
        return MongoClients.create();
    }

    @Override
    protected String getDatabaseName() {
        return "reactive";
    }
}

要在响应式MongoDB中使用事务,我们需要使用ReactiveMongoOperations中的inTransaction()方法:

@Autowired
private ReactiveMongoOperations reactiveOps;

@Test
public void whenPerformTransaction_thenSuccess() {
    User user1 = new User("Jane", 23);
    User user2 = new User("John", 34);
    reactiveOps.inTransaction()
        .execute(action -> action.insert(user1)
        .then(action.insert(user2)));
}

此处提供了有关Spring Data中的响应式Repository的更多信息。

8. 总结

在这篇文章中,我们学习了如何使用Spring Data使用原生和非原生MongoDB事务。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章