Visão geral
O Spring Boot é uma estrutura Java de código aberto que simplifica o desenvolvimento de aplicativos prontos para produção. Quando combinada com o Spring Data MongoDB, essa estrutura fornece uma maneira eficiente de interagir com bancos de dados MongoDB .
Este tutorial demonstra como construir um aplicação reativo de inicialização de inicialização que utiliza o Spring Data MongoDB para executar operações em um banco de dados MongoDB . Você pode usar esse exemplo de aplicação 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 multidocumentos
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 aplicação de amostra neste tutorial configura o suporte a transações para garantir a atomicidade das operações do banco de dados .
Para saber mais sobre transações MongoDB , consulte Transações no manual do MongoDB Server .
Tutorial
Este tutorial mostra como baixar um exemplo de aplicação que implementa um sistema simplificado de saldo de caixa. O aplicação permite criar, recuperar e atualizar o saldo de contas bancárias. Para visualizar a aplicação completa, consulte o repositório GitHub mdb-spring-boot-reactive.
Conclua o tutorial para saber como executar as seguintes ações:
Baixe um exemplo de aplicação Spring Boot
Configure o aplicação para se conectar ao MongoDB
Compreender a estrutura do aplicação e os principais componentes
Execute o aplicativo
Enviar solicitações POST para criar contas bancárias e realizar transações
Faça o download 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 aplicação de exemplo do repositório do MongoDB Developer GitHub executando o seguinte comando:
git clone git@github.com:mongodb-developer/mdb-spring-boot-reactive.git
Este repositório contém um aplicação 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 aplicação 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 aplicação:
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 endpoints de gerenciamento de contas
O arquivo AccountController.java contém endpoints da API REST para criar e buscar contas. O arquivo define um endpoint de método POST que insere um documento na coleção txn-demo.accounts e um endpoint 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 endpoint retorna um tipo Mono<Account> de AccountRepository, uma interface ReactiveMongoRepository que atua como uma abstração do driver Java Reactive Streams subjacente.
Revise os endpoints da transação de saldo
A classe AccountController também inclui os seguintes endpoints de transação:
Um endpoint
.../debitque adiciona ao saldo de uma contaUm endpoint
.../creditque subtrai de um saldo de contaUm endpoint
.../transferque executa uma transferência de uma conta para outra
Esses endpoints 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 endpoints de crédito e crédito criam um novo objeto TxnEntry, e o endpoint 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 atualização 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 endpoint POST descrito em uma etapa anterior utilize o accountRepository.save() método, você não precisa definir este método. O save() método e muitos outros métodos básicos já estão declarados por interfaces na cadeia de herança ReactiveMongoRepository de.
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 com vários documentos. 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 aplicação 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.
Teste o Aplicativo
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 endpoint /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 endpoint .../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 endpoint .../transfer para concluir a transferência de saldo.
Recursos adicionais
Para saber mais sobre o Spring Data MongoDB, consulte a documentação de referência do Spring Data MongoDB .
Para visualizar o aplicação de exemplo completo, consulte o repositório GitHub mdb-spring-boot-reactive.