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.