sql >> Base de Datos >  >> NoSQL >> MongoDB

Transacciones de Spring Data MongoDB

1. Resumen

A partir de la versión 4.0, MongoDB admite transacciones ACID de varios documentos. Y, Spring Data Lovelace ahora brinda soporte para estas transacciones nativas de MongoDB .

En este tutorial, analizaremos la compatibilidad con Spring Data MongoDB para transacciones sincrónicas y reactivas.

También echaremos un vistazo a Spring Data TransactionTemplate para soporte de transacciones no nativas.

Para obtener una introducción a este módulo Spring Data, eche un vistazo a nuestro artículo introductorio.

2. Configurar MongoDB 4.0

Primero, necesitaremos configurar la última versión de MongoDB para probar la nueva compatibilidad con transacciones nativas.

Para comenzar, debemos descargar la última versión del Centro de descargas de MongoDB.

A continuación, comenzaremos mongod servicio usando la línea de comando:

mongod --replSet rs0

Finalmente, inicie el conjunto de réplicas, si aún no lo ha hecho:

mongo --eval "rs.initiate()"

Tenga en cuenta que MongoDB actualmente admite transacciones a través de un conjunto de réplicas.

3. Configuración Maven

A continuación, debemos agregar las siguientes dependencias a nuestro pom.xml :

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

La última versión de la biblioteca se puede encontrar en el repositorio central

4. Configuración de MongoDB

Ahora, echemos un vistazo a nuestra configuración:

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

Tenga en cuenta que necesitamos registrar MongoTransactionManager en nuestra configuración para habilitar las transacciones nativas de MongoDB, ya que están deshabilitadas de manera predeterminada.

5. Transacciones síncronas

Después de terminar la configuración, todo lo que tenemos que hacer para usar transacciones MongoDB nativas es anotar nuestro método con @Transaccional .

Todo lo que esté dentro del método anotado se ejecutará en una sola transacción:

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

Tenga en cuenta que no podemos usar listCollections comando dentro de una transacción de varios documentos, por ejemplo:

@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 ejemplo arroja una MongoTransactionException como usamos collectionExists() método.

6. Plantilla de transacción

Vimos cómo Spring Data admite la nueva transacción nativa de MongoDB. Además, Spring Data también ofrece la opción no nativa.

Podemos realizar transacciones no 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));
}

Necesitamos configurar SessionSynchronization a SIEMPRE para usar transacciones Spring Data no nativas.

7. Transacciones reactivas

Por último, echaremos un vistazo a la compatibilidad de Spring Data con las transacciones reactivas de MongoDB .

Tendremos que agregar algunas dependencias más al pom.xml para trabajar con MongoDB reactivo:

<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>

Las dependencias mongodb-driver-reactivestreams, mongodb-driver-sync y reactor-test están disponibles en Maven Central.

Y por supuesto, necesitamos configurar nuestra 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 transacciones en MongoDB reactivo, necesitamos usar inTransaction() método en 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)));
}

Más información sobre repositorios reactivos en Spring Data está disponible aquí.