Spring Data MongoDB Transactions – Spring Data MongoDB事务

最后修改: 2018年 10月 6日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Starting from the 4.0 release, MongoDB supports multi-document ACID transactions. And, Spring Data Lovelace now provides support for these native MongoDB transactions.

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

In this tutorial, we’ll discuss Spring Data MongoDB support for synchronous and reactive transactions.

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

We’ll also take a look at Spring Data TransactionTemplate for non-native transactions support.

我们还将看看Spring Data TransactionTemplate对非本地事务的支持。

For an introduction to this Spring Data module, have a look at our introductory write-up.

关于这个Spring Data模块的介绍,请看我们的介绍性的文章

2. Setup MongoDB 4.0

2.设置MongoDB 4.0

First, we’ll need to setup latest MongoDB to try the new native transactions support.

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

To get started, we have to download the latest version from the MongoDB Download Center.

要开始工作,我们必须从MongoDB下载中心下载最新版本。

Next, we’ll start mongod service using the command line:

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

mongod --replSet rs0

Finally, initiate replica set – if not already:

最后,启动复制集–如果还没有的话。

mongo --eval "rs.initiate()"

Note that MongoDB currently supports transactions over a replica set.

注意,MongoDB目前支持通过复制集进行交易。

3. Maven Configuration

3.Maven配置

Next, we need to add the following dependencies to our pom.xml:

接下来,我们需要在我们的pom.xml中添加以下依赖项。

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

The latest release of the library can be found on the Central Repository

库的最新版本可以在中央存储库上找到。

4. MongoDB Configuration

4.MongoDB配置

Now, let’s take a look at our configuration:

现在,让我们看一下我们的配置。

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

Note that we need to register MongoTransactionManager in our configuration to enable native MongoDB transactions as they are disabled by default.

请注意,我们需要在配置中注册MongoTransactionManager以启用本地MongoDB事务,因为它们在默认情况下是禁用的。

5. Synchronous Transactions

5.同步事务

After we finished the configuration, all we need to do to use native MongoDB transactions – is to annotate our method with @Transactional.

在我们完成配置后,我们需要做的就是使用原生的MongoDB事务–@Transactional.注解我们的方法。

Everything inside the annotated method will be executed in one transaction:

被注释的方法中的所有内容都将在一个事务中执行。

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

Note that we can’t use listCollections command inside a multi-document transaction – for example:

请注意,我们不能在一个多文档事务中使用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));
    }
}

This example throws a MongoTransactionException as we used the collectionExists() method.

这个例子抛出了一个MongoTransactionException,因为我们使用了collectionExists()方法。

6. TransactionTemplate

6.TransactionTemplate

We saw how Spring Data support new MongoDB native transaction. Additionally, Spring Data also provides the non-native option.

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

We can perform non-native transactions using Spring Data 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));
}

We need to set SessionSynchronization to ALWAYS to use non-native Spring Data transactions.

我们需要将SessionSynchronization设置为ALWAYS,以使用非本地的Spring Data事务。

7. Reactive Transactions

7.反应式事务

Finally, we’ll take a look at Spring Data support for MongoDB reactive transactions.

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

We’ll need to add a few more dependencies to the pom.xml to work with reactive 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>

The mongodb-driver-reactivestreams, mongodb-driver-sync and reactor-test dependencies are available on Maven Central.

mongodb-driver-reactivestreamsmongodb-driver-sync 和 reactor-test依赖项可在Maven Central获得。

And of course, we need to configure our Reactive MongoDB:

当然,我们还需要配置我们的Reactive 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";
    }
}

To use transactions in reactive MongoDB, we need to use the inTransaction() method in ReactiveMongoOperations:

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

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

More information on reactive repositories in Spring Data is available here.

有关 Spring Data 中的反应式存储库的更多信息可在此处获得。

8. Conclusion

8.结论

In this write-up, we learned how to use native and non-native MongoDB transactions using Spring Data.

在本篇文章中,我们学习了如何使用Spring Data的本地和非本地MongoDB事务。

The full source code for the examples is available over on GitHub.

示例的完整源代码可在GitHub上获得