MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Transações do Spring Data MongoDB

1. Visão geral


A partir da versão 4.0, o MongoDB oferece suporte a transações ACID de vários documentos. E, Spring Data Lovelace agora oferece suporte para essas transações nativas do MongoDB .

Neste tutorial, discutiremos o suporte do Spring Data MongoDB para transações síncronas e reativas.

Também veremos o Spring Data TransactionTemplate para suporte a transações não nativas.

Para uma introdução a este módulo Spring Data, dê uma olhada em nosso artigo introdutório.

2. Configurar o MongoDB 4.0


Primeiro, precisaremos configurar o MongoDB mais recente para experimentar o novo suporte a transações nativas.

Para começar, precisamos baixar a versão mais recente do Centro de Download do MongoDB.

Em seguida, iniciaremos o mongod serviço usando a linha de comando:
mongod --replSet rs0

Por fim, inicie o conjunto de réplicas – se ainda não:
mongo --eval "rs.initiate()"

Observe que o MongoDB atualmente suporta transações em um conjunto de réplicas.

3. Configuração do Maven


Em seguida, precisamos adicionar as seguintes dependências ao nosso pom.xml :
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-mongodb</artifactId>
    <version>3.0.3.RELEASE</version>
</dependency>

A última versão da biblioteca pode ser encontrada no Repositório Central

4. Configuração do MongoDB


Agora vamos dar uma olhada na nossa configuração:
@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);
    }
}

Observe que precisamos registrar MongoTransactionManager em nossa configuração para habilitar transações nativas do MongoDB, pois elas estão desabilitadas por padrão.

5. Transações síncronas


Após terminarmos a configuração, tudo o que precisamos fazer para usar transações nativas do MongoDB – é anotar nosso método com @Transactional .

Tudo dentro do método anotado será executado em uma transação:
@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));
}

Observe que não podemos usar listCollections comando dentro de uma transação de vários documentos – por exemplo:
@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));
    }
}

Este exemplo lança uma MongoTransactionException como usamos o collectionExists() método.

6. Modelo de transação


Vimos como o Spring Data suporta a nova transação nativa do MongoDB. Além disso, o Spring Data também fornece a opção não nativa.

Podemos realizar transações não nativas usando 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));
}

Precisamos definir SessionSynchronization para SEMPRE para usar transações não nativas do Spring Data.

7. Transações reativas


Por fim, veremos o Suporte de Spring Data para transações reativas do MongoDB .

Precisaremos adicionar mais algumas dependências ao pom.xml para trabalhar com MongoDB reativo:
<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>

As dependências mongodb-driver-reactivestreams, mongodb-driver-sync e react-test estão disponíveis no Maven Central.

E claro, precisamos configurar nosso 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";
    }
}

Para usar transações no MongoDB reativo, precisamos usar o inTransaction() método em 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)));
}

Mais informações sobre repositórios reativos no Spring Data estão disponíveis aqui.