Spring Data MongoDB Транзакции

Spring Data MongoDB Сделки

1. обзор

Начиная с версии 4.0, MongoDB поддерживает транзакции ACID с несколькими документами. И,Spring Data Lovelace now provides support for these native MongoDB transactions.

В этом руководстве мы обсудим поддержку Spring Data MongoDB для синхронных и реактивных транзакций.

Мы также рассмотрим Spring DataTransactionTemplate для поддержки неродных транзакций.

Чтобы познакомиться с этим модулем Spring Data, взгляните на нашintroductory write-up.

2. Настройка MongoDB 4.0

Во-первых, нам нужно установить последнюю версию MongoDB, чтобы попробовать новую поддержку собственных транзакций.

Для начала мы должны загрузить последнюю версию сMongoDB Download Center.

Затем мы запустим службуmongod с помощью командной строки:

mongod --replSet rs0

Наконец, инициируйте набор реплик - если еще не:

mongo --eval "rs.initiate()"

Обратите внимание, что MongoDB в настоящее время поддерживает транзакции через набор реплик.

3. Конфигурация Maven

Затем нам нужно добавить следующие зависимости к нашемуpom.xml:


    org.springframework.data
    spring-data-mongodb
    2.1.0.RELEASE



    org.springframework.data
    spring-data-releasetrain
    Lovelace-M3
    pom
    import

Обратите внимание, что нам также нужно добавить репозиторий вех в нашpom.xml:


    
        spring-milestones
        Spring Milestones
        https://repo.spring.io/milestone
        
            false
        
    

Последнюю версию библиотеки можно найти наCentral Repository

4. Конфигурация MongoDB

Теперь давайте посмотрим на нашу конфигурацию:

@Configuration
@EnableMongoRepositories(basePackages = "com.example.repository")
public class MongoTransactionConfig extends AbstractMongoConfiguration{

    @Bean
    MongoTransactionManager transactionManager(MongoDbFactory dbFactory) {
        return new MongoTransactionManager(dbFactory);
    }

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

    @Override
    public MongoClient mongoClient() {
        return new MongoClient("127.0.0.1", 27017);
    }
}

Обратите внимание, чтоwe need to register MongoTransactionManager в нашей конфигурации разрешает собственные транзакции MongoDB, поскольку они отключены по умолчанию.

5. Синхронные Сделки

После того, как мы закончили настройку, все, что нам нужно сделать, чтобы использовать собственные транзакции MongoDB, - этоannotate our method with*@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 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));
    }
}

В этом примере выдаетсяMongoTransactionException, поскольку мы использовали методcollectionExists().

Мы также не можем запускатьcount внутри многодокументной транзакции:

@Test(expected = MongoCommandException.class)
@Transactional
public void whenCountDuringMongoTransaction_thenException() {
    userRepository.save(new User("John", 30));
    userRepository.save(new User("Ringo", 35));
    userRepository.count();
}

Но мы можем обойти это простым запросом и затем получить размер полученного списка:

@Test
@Transactional
public void whenQueryDuringMongoTransaction_thenSuccess() {
    userRepository.save(new User("Jane", 20));
    userRepository.save(new User("Nick", 33));
    List users = mongoTemplate.find(new Query(), User.class);

    assertTrue(users.size() > 1);
}

6. TransactionTemplateс

Мы увидели, как Spring Data поддерживает новую собственную транзакцию MongoDB. Кроме того, Spring Data также предоставляет неродную опцию.

We can perform non-native transactions using 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 users = mongoTemplate.find(query, User.class);

    assertThat(users.size(), is(1));
}

Нам нужно установитьSessionSynchronization наALWAYS, чтобы использовать неродные транзакции Spring Data.

7. Реактивные транзакции

Наконец, взглянем наSpring Data support for MongoDB reactive transactions.

Нам нужно добавить еще несколько зависимостей кpom.xml для работы с реактивным MongoDB:


    org.mongodb
    mongodb-driver-reactivestreams
    1.9.2



    io.projectreactor
    reactor-test
    3.2.0.RELEASE
    test

Зависимостиmongodb-driver-reactivestreams иreactor-test доступны в Maven Central.

И, конечно же, нам нужно настроить нашу Reactive MongoDB:

@Configuration
@EnableReactiveMongoRepositories(basePackages
  = "com.example.reactive.repository")
public class MongoReactiveConfig
  extends AbstractReactiveMongoConfiguration {

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

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

Чтобы использовать транзакции в реактивном 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)));
}

Дополнительная информация о реактивных репозиториях в Spring Data доступнаhere.

8. Заключение

В этой статье мы узнали, как использовать нативные и не нативные транзакции MongoDB с использованием Spring Data.

Доступен полный исходный код примеровover on GitHub.