Spring Data MongoDB Transactions

Spring Data MongoDB Transactions

1. Vue d'ensemble

À partir de la version 4.0, MongoDB prend en charge les transactions ACID multi-documents. Et,Spring Data Lovelace now provides support for these native MongoDB transactions.

Dans ce didacticiel, nous aborderons la prise en charge de Spring Data MongoDB pour les transactions synchrones et réactives.

Nous examinerons également Spring DataTransactionTemplate pour la prise en charge des transactions non natives.

Pour une introduction à ce module Spring Data, jetez un œil à nosintroductory write-up.

2. Configurer MongoDB 4.0

Tout d'abord, nous devons configurer la dernière version de MongoDB pour essayer la nouvelle prise en charge des transactions natives.

Pour commencer, nous devons télécharger la dernière version depuis leMongoDB Download Center.

Ensuite, nous allons démarrer le servicemongod en utilisant la ligne de commande:

mongod --replSet rs0

Enfin, lancez le jeu de réplicas - si ce n'est déjà fait:

mongo --eval "rs.initiate()"

Notez que MongoDB prend actuellement en charge les transactions sur un jeu de réplicas.

3. Configuration Maven

Ensuite, nous devons ajouter les dépendances suivantes à nospom.xml:


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



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

Notez que nous devons également ajouter le référentiel de jalons à nospom.xml:


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

La dernière version de la bibliothèque est disponible sur leCentral Repository

4. Configuration de MongoDB

Voyons maintenant notre configuration:

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

Notez quewe need to register MongoTransactionManager dans notre configuration permet d'activer les transactions MongoDB natives car elles sont désactivées par défaut.

5. Transactions synchrones

Une fois la configuration terminée, tout ce que nous devons faire pour utiliser les transactions MongoDB natives est deannotate our method with*@Transactional*.

Tout ce qui se trouve dans la méthode annotée sera exécuté dans une 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 users = mongoTemplate.find(query, User.class);

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

Notez que nous ne pouvons pas utiliser la commandelistCollections dans une transaction multi-document - par exemple:

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

Cet exemple lance unMongoTransactionException car nous avons utilisé la méthodecollectionExists().

Nous ne pouvons pas non plus exécutercount dans une transaction multi-document:

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

Mais nous pouvons contourner celle-ci avec une requête simple, puis obtenir la taille de la liste résultante:

@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

Nous avons vu comment Spring Data prend en charge la nouvelle transaction native MongoDB. De plus, Spring Data fournit également l'option non native.

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

Nous devons définirSessionSynchronization surALWAYS pour utiliser des transactions Spring Data non natives.

7. Transactions réactives

Enfin, nous allons jeter un œil àSpring Data support for MongoDB reactive transactions.

Nous devrons ajouter quelques dépendances supplémentaires auxpom.xml pour travailler avec MongoDB réactif:


    org.mongodb
    mongodb-driver-reactivestreams
    1.9.2



    io.projectreactor
    reactor-test
    3.2.0.RELEASE
    test

Les dépendancesmongodb-driver-reactivestreams etreactor-test sont disponibles sur Maven Central.

Et bien sûr, nous devons configurer notre MongoDB réactif:

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

Pour utiliser des transactions dans MongoDB réactif, nous devons utiliser la méthodeinTransaction() dansReactiveMongoOperations:

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

Plus d'informations sur les référentiels réactifs dans Spring Data sont disponibleshere.

8. Conclusion

Dans cet article, nous avons appris à utiliser des transactions MongoDB natives et non natives à l'aide de Spring Data.

Le code source complet des exemples est disponibleover on GitHub.