Visão geral
Spring Boot é um framework Java de código aberto que simplifica o desenvolvimento de aplicativos prontos para produção. Quando combinada com Spring Data MongoDB, esse framework fornece uma maneira eficiente de interagir com bancos de dados MongoDB.
Este tutorial demonstra como criar um aplicativo reativo Spring Boot que utiliza o Spring Data MongoDB para executar operações em um banco de dados MongoDB. Você pode usar essa amostra de aplicativo de saldo de caixa para chamar APIs REST que executam as seguintes ações:
Criar ou buscar uma conta
Realizar transações em uma conta ou entre duas contas
Spring Data MongoDB
Spring Data MongoDB fornece suporte de repositório para MongoDB, oferecendo duas maneiras principais de interagir com o banco de dados:
ReactiveMongoRepository: Uma abstração de nível superior que fornece acesso a operações comuns do banco de dados
ReactiveMongoTemplate: Uma abstração de nível inferior que oferece mais controle sobre as operações do MongoDB e a construção de queries
Transações ACID multidocumento
O MongoDB oferece suporte a transações ACID de vários documentos, que permitem executar várias operações que atendem garantias de atomicidade, consistência, isolamento e durabilidade. O Spring Data MongoDB oferece suporte integrado para transações por meio da anotação @Transactional ou da classe TransactionalOperator. O aplicativo de amostra neste tutorial configura o suporte a transações para garantir a atomicidade das operações do banco de dados.
Para aprender mais sobre transações MongoDB, consulte Transações no manual do MongoDB Server.
Tutorial
Este tutorial mostra como baixar um exemplo de aplicativo que implementa um sistema simplificado de saldo de caixa. O aplicativo permite criar, recuperar e atualizar o saldo de contas bancárias. Para visualizar o aplicativo completo, consulte o repositório GitHub mdb-spring-boot-reactive.
Conclua o tutorial para aprender como executar as seguintes ações:
Baixe um exemplo de aplicativo Spring Boot
Configure o aplicativo para se conectar ao MongoDB
Compreender a estrutura do aplicativo e os principais componentes
Execute o aplicativo
Enviar solicitações POST para criar contas bancárias e realizar transações
Baixe e configure sua conexão
Verifique os pré-requisitos
Antes de iniciar este tutorial, verifique se você tem os seguintes componentes preparados:
Conta do MongoDB Atlas com um cluster configurado. Para saber como criar um cluster, consulte o guia de Introdução ao MongoDB.
Java 21 ou posterior.
Maven 3.5 ou posterior.
Baixe o aplicação de exemplo
Clone o aplicativo de exemplo do repositório do MongoDB desenvolvedor GitHub executando o seguinte comando:
git clone git@github.com:mongodb-developer/mdb-spring-boot-reactive.git
Este repositório contém um aplicativo reativo Spring Boot que usa o Spring Data MongoDB para interagir com um banco de dados MongoDB.
Configurar sua conexão MongoDB
Navegue até o arquivo src/main/resources/application.properties no diretório do aplicativo de exemplo. Neste arquivo, defina a propriedade spring.data.mongodb.uri para seu URI de conexão do Atlas , conforme mostrado no código a seguir:
spring.data.mongodb.uri=<connection URI>
Substitua o espaço reservado <connection URI> pelo URI de conexão do Atlas .
Habilitar validação de esquema
No diretório raiz, execute o seguinte comando para configurar a validação de esquema para seu aplicativo:
mongosh "<connection URI>" --file setup.js
Este comando cria uma restrição que garante que o saldo da conta bancária nunca fique abaixo de 0. Substitua o espaço reservado <connection URI> pelo URI de conexão do Atlas .
Compreender a estrutura do aplicativo
Revise os pontos de extremidade de gerenciamento de contas
O arquivo AccountController.java contém pontos de extremidade da REST API para criar e buscar contas. O arquivo define um ponto de extremidade de método POST que insere um documento na coleção txn-demo.accounts e um ponto de extremidade de método GET que encontra um documento com base em seu valor de accountNum. O seguinte código mostra estes métodos:
public class AccountController { //... public Mono<Account> createAccount( Account account) { return accountRepository.save(account); } public Mono<Account> getAccount( String accountNum) { return accountRepository.findByAccountNum(accountNum) .switchIfEmpty(Mono.error(new AccountNotFoundException())); } //... }
Cada ponto de extremidade retorna um tipo Mono<Account> de AccountRepository, uma interface ReactiveMongoRepository que atua como uma abstração do driver Java Reactive Streams subjacente.
Revise os pontos de extremidade da transação de saldo
A classe AccountController também inclui os seguintes pontos de extremidade de transação:
Um
.../debitponto de extremidade que adiciona ao saldo de uma contaUm
.../creditponto de extremidade que subtrai de um saldo de contaUm
.../transferponto de extremidade que executa uma transferência de uma conta para outra
Esses pontos de extremidade têm as seguintes definições:
public class AccountController { //... public Mono<Txn> debitAccount( String accountNum, Map<String, Object> requestBody) { //... txn.addEntry(new TxnEntry(accountNum, amount)); return txnService.saveTransaction(txn).flatMap(txnService::executeTxn); } public Mono<Txn> creditAccount( String accountNum, Map<String, Object> requestBody) { //... txn.addEntry(new TxnEntry(accountNum, -amount)); return txnService.saveTransaction(txn).flatMap(txnService::executeTxn); } public Mono<Txn> transfer( String from, TransferRequest transferRequest) { //... txn.addEntry(new TxnEntry(from, -amount)); txn.addEntry(new TxnEntry(to, amount)); return txnService.saveTransaction(txn).flatMap(txnService::executeTxn); } //... }
Um objeto TxnEntry representa uma alteração em uma única conta, e um Txn pode consistir em um ou vários objetos TxnEntry. No código de amostra, os pontos de extremidade de débito e crédito criam um novo objeto TxnEntry, e o ponto de extremidade de transferência cria dois objetos TxnEntry.
Revise os métodos de query personalizada
A interface do AccountRepository estende o ReactiveMongoRepository e define os seguintes métodos de query:
public interface AccountRepository extends ReactiveMongoRepository<Account, String> { Mono<Account> findByAccountNum(String accountNum); Mono<Long> findAndIncrementBalanceByAccountNum(String accountNum, double increment); }
Os códigos usam as seguintes anotações que permitem usar espaços reservados ao executar query do MongoDB, que são dinamicamente substituídos por argumentos do método:
@Query: Anota o métodofindByAccountNum()e especifica os critérios de query para localizar documentos. O espaço reservado?0é substituído pelo valor de parâmetroaccountNum.@Update: anota o métodofindAndIncrementBalanceByAccountNum()e especifica a operação de atualizar a ser executada nos documentos correspondentes. O espaço reservado?1é substituído pelo valor do parâmetroincrementpara aumentar o equilíbrio usando o operador$incdo MongoDB.
Observação
Embora o ponto de extremidade publicação descrito em uma etapa anterior utilize o método accountRepository.save(), você não precisa definir este método. O método save() e muitos outros métodos básicos já estão declarados por interfaces na cadeia de herança de ReactiveMongoRepository.
Entender o serviço de transações
A classe TxnService lida com a execução da transação. Esta classe inclui o seguinte código:
public class TxnService { //... public Mono<Txn> saveTransaction(Txn txn) { return txnTemplate.save(txn); } public Mono<Txn> executeTxn(Txn txn) { return updateBalances(txn) .onErrorResume(DataIntegrityViolationException.class /*lambda expression to handle error*/) .onErrorResume(AccountNotFoundException.class /*lambda expression to handle error*/) .then(txnTemplate.findAndUpdateStatusById(txn.getId(), TxnStatus.SUCCESS)); } public Flux<Long> updateBalances(Txn txn) { Flux<Long> updatedCounts = Flux.fromIterable(txn.getEntries()).concatMap( entry -> accountRepository.findAndIncrementBalanceByAccountNum( entry.getAccountNum(), entry.getAmount()) ); return updatedCounts.handle(/*...*/); } }
A classe TxnService inclui os seguintes métodos:
saveTransaction(): salva um documentoTxnna coleçãotransactionsexecuteTxn(): chama o métodoupdateBalances()e atualiza o status da transação no documentoTxnupdateBalances(): Itera por cadaTxnEntrye faz as atualizações correspondentes a cada documentoaccount
Revise o modelo de transação
Os métodos saveTransaction() e executeTxn() descritos na etapa anterior usam métodos definidos na classe TxnTemplate . Esses métodos têm as seguintes definições:
public class TxnTemplate { //... public Mono<Txn> save(Txn txn) { return template.save(txn); } public Mono<Txn> findAndUpdateStatusById(String id, TxnStatus status) { Query query = query(where("_id").is(id)); Update update = update("status", status); FindAndModifyOptions options = FindAndModifyOptions.options().returnNew(true); return template.findAndModify(query, update, options, Txn.class); } //... }
Estes métodos interagem com MongoDB utilizando o ReactiveMongoTemplate.
Configurar transações multidocumento
Ao transferir dinheiro entre contas, você pode usar uma transação multidocumento. As atualizações em duas contas devem ser atômicas, e as transações garantem a atomicidade dos dados.
Para acessar o suporte a transações do Spring, o aplicativo de amostra adiciona o ReactiveMongoTransactionManager bean ao arquivo ReactiveMongoConfig.java:
public class ReactiveMongoConfig extends AbstractReactiveMongoConfiguration { //... ReactiveMongoTransactionManager transactionManager(ReactiveMongoDatabaseFactory dbFactory) { return new ReactiveMongoTransactionManager(dbFactory); } }
Você pode definir o escopo de uma transação usando um objeto TransactionalOperator ou a anotação @Transactional. A classe TxnService mostra ambas as abordagens.
Dica
Transações de dados da primavera
Para aprender mais sobre transações e sessões no Spring Data MongoDB, consulte Sessões e transações na documentação do Spring Data.
Teste o Aplicativo
Execute o aplicativo
Para iniciar o aplicativo, execute os seguintes comandos no diretório raiz do projeto:
mvn spring-boot:run
Após iniciar o aplicativo, você pode acessá-lo em http://localhost:8080. Em seguida, você pode usar os pontos de extremidade da REST API para criar contas e executar transações.
Criar uma Conta
Para criar uma nova conta bancária que tenha um número de conta de 12345, execute o seguinte comando na sua shell:
curl --location 'localhost:8080/account' \ --header 'Content-Type: application/json' \ --data '{ "accountNum": "12345" }'
Este comando envia uma solicitação POST para o ponto de extremidade /account para criar um novo documento de conta bancária na coleção accounts.
Aumente o saldo da sua conta
Para devolver o valor à conta criada na etapa anterior, execute o seguinte comando em seu shell:
curl --location 'localhost:8080/account/12345/debit' \ --header 'Content-Type: application/json' \ --data '{ "amount": 1000 }'
Este comando envia uma solicitação ao ponto de extremidade .../debit para aumentar o valor amount do documento account correspondente em 1000.
Transferir dinheiro entre contas
Para transferir dinheiro de uma conta para outra, crie uma nova conta que tenha um número de conta de 67890:
curl --location 'localhost:8080/account' \ --header 'Content-Type: application/json' \ --data '{ "accountNum": "67890" }'
Em seguida, transfira 500 dólares para esta nova conta executando o seguinte comando:
curl --location 'localhost:8080/account/12345/transfer' \ --header 'Content-Type: application/json' \ --data '{ "to": "67890", "amount": 500 }'
Este comando envia uma solicitação para o ponto de extremidade .../transfer para concluir a transferência de saldo.
Recursos adicionais
Para aprender mais sobre o Spring Data MongoDB, consulte a documentação de referência do Spring Data MongoDB.
Para visualizar o aplicativo de exemplo completo, consulte o repositório Github mdb-spring-boot-reactive.