Overview
Spring Boot es un framework Java de código abierto que simplifica el desarrollo de aplicaciones listas para producción. Al combinarse con Spring Data MongoDB, este framework proporciona una forma eficiente de interactuar con bases de datos MongoDB.
Este tutorial muestra cómo crear una aplicación reactiva de Spring Boot que utiliza Spring Data MongoDB para realizar operaciones en una base de datos MongoDB. Puede usar esta aplicación de saldo de caja de ejemplo para llamar a las API REST que realizan las siguientes acciones:
Crear o obtener una cuenta
Realizar transacciones en una cuenta o entre dos cuentas
Datos de primavera MongoDB
Spring Data MongoDB proporciona soporte de repositorio para MongoDB, ofreciendo dos formas principales de interactuar con la base de datos:
ReactiveMongoRepository: una abstracción de nivel superior que proporciona acceso a operaciones de base de datos comunes
ReactiveMongoTemplate: una abstracción de nivel inferior que ofrece más control sobre las operaciones de MongoDB y la construcción de consultas
Transacciones ACID de múltiples documentos
MongoDB admite transacciones ACID multidocumento, lo que permite realizar múltiples operaciones que cumplen con las garantías de atomicidad, consistencia, aislamiento y durabilidad. Spring Data MongoDB ofrece compatibilidad integrada con transacciones a través de @Transactional Anotación o la clase TransactionalOperator. La aplicación de ejemplo de este tutorial configura el soporte de transacciones para garantizar la atomicidad de las operaciones de la base de datos.
Para obtener más información sobre las transacciones de MongoDB, consulte Transacciones en el manual del servidor MongoDB.
Tutorial
Este tutorial muestra cómo descargar una aplicación de ejemplo que implementa un sistema simplificado de saldo de caja. La aplicación permite crear, recuperar y actualizar el saldo de cuentas bancarias. Para ver la aplicación completa, consulte el repositorio de GitHub mdb-spring-boot-reactive.
Complete el tutorial para aprender a realizar las siguientes acciones:
Descargue una aplicación Spring Boot de ejemplo
Configurar la aplicación para conectarse a MongoDB
Comprender la estructura de la aplicación y los componentes clave
Ejecutar la aplicación
Enviar solicitudes POST para crear cuentas bancarias y realizar transacciones
Descargue y configure su conexión
Descargar la aplicación de ejemplo
Clone la aplicación de ejemplo del repositorio GitHub de MongoDB Developer ejecutando el siguiente comando:
git clone git@github.com:mongodb-developer/mdb-spring-boot-reactive.git
Este repositorio contiene una aplicación Spring Boot reactiva que utiliza Spring Data MongoDB para interactuar con una base de datos MongoDB.
Configurar su conexión MongoDB
Navegue al archivo src/main/resources/application.properties en el directorio de la aplicación de ejemplo. En este archivo, configure la propiedad spring.data.mongodb.uri con la URI de conexión de Atlas, como se muestra en el siguiente código:
spring.data.mongodb.uri=<connection URI>
Reemplace el marcador de posición <connection URI> con su URI de conexión Atlas.
Habilitar la validación del esquema
Desde el directorio raíz, ejecute el siguiente comando para configurar la validación del esquema para su aplicación:
mongosh "<connection URI>" --file setup.js
Este comando crea una restricción que garantiza que el saldo de la cuenta bancaria nunca sea inferior a 0. Reemplace el marcador <connection URI> con la URI de su conexión de Atlas.
Comprender la estructura de la aplicación
Revisar los puntos finales de administración de cuentas
El archivo AccountController.java contiene los puntos finales de la API REST para crear y obtener cuentas. El archivo define un punto final del método POST que inserta un documento en la colección txn-demo.accounts y un punto final del método GET que encuentra un documento según su valor accountNum. El siguiente código muestra estos 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 punto final devuelve un tipo Mono<Account> de AccountRepository, una interfaz ReactiveMongoRepository que actúa como una abstracción del controlador Java Reactive Streams subyacente.
Revisar los puntos finales de las transacciones de saldo
La clase AccountController también incluye los siguientes puntos finales de transacción:
Un punto final
.../debitque se suma al saldo de una cuentaUn punto final
.../creditque resta del saldo de una cuentaUn punto final
.../transferque realiza una transferencia de una cuenta a otra
Estos puntos finales tienen las siguientes definiciones:
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); } //... }
Un objeto TxnEntry representa un cambio en una sola cuenta, y un objeto Txn puede constar de uno o varios objetos TxnEntry. En el código de ejemplo, los puntos de conexión de débito y crédito crean un nuevo objeto TxnEntry y el punto de conexión de transferencia crea dos objetos TxnEntry.
Revisar los métodos de consulta personalizados
La interfaz AccountRepository extiende ReactiveMongoRepository y define los siguientes métodos de consulta:
public interface AccountRepository extends ReactiveMongoRepository<Account, String> { Mono<Account> findByAccountNum(String accountNum); Mono<Long> findAndIncrementBalanceByAccountNum(String accountNum, double increment); }
Los códigos utilizan las siguientes anotaciones que le permiten utilizar marcadores de posición cuando consulta MongoDB, que se sustituyen dinámicamente con argumentos de método:
@Query: Anota el métodofindByAccountNum()y especifica los criterios de consulta para encontrar documentos. El marcador?0se sustituye por el valor del parámetroaccountNum.@Update: Anota el métodofindAndIncrementBalanceByAccountNum()y especifica la operación de actualización que se realizará en los documentos coincidentes. El marcador?1se sustituye por el valor del parámetroincrementpara aumentar el saldo mediante el operador$incde MongoDB.
Nota
Aunque el punto final POST descrito en un paso anterior utiliza el accountRepository.save() método, no es necesario definirlo. El save() método y muchos otros métodos base ya están declarados por interfaces en la cadena de herencia ReactiveMongoRepository de.
Entender el servicio de transacciones
La clase TxnService gestiona la ejecución de transacciones. Esta clase incluye el siguiente 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(/*...*/); } }
La clase TxnService incluye los siguientes métodos:
saveTransaction(): Guarda un documentoTxnen la coleccióntransactionsexecuteTxn(): Llama al métodoupdateBalances()y luego actualiza el estado de la transacción en el documentoTxnupdateBalances(): Itera a través de cadaTxnEntryy realiza las actualizaciones correspondientes en cada documentoaccount
Revisar la plantilla de transacción
Los métodos saveTransaction() y executeTxn() descritos en el paso anterior utilizan métodos definidos en la clase TxnTemplate. Estos métodos tienen las siguientes definiciones:
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); } //... }
Estos métodos interactúan con MongoDB mediante ReactiveMongoTemplate.
Configurar transacciones de múltiples documentos
Al transferir dinero entre cuentas, puede usar una transacción multidocumento. Las actualizaciones entre dos cuentas deben ser atómicas, y las transacciones garantizan la atomicidad de los datos.
Para acceder al soporte de transacciones de Spring, la aplicación de muestra agrega el bean ReactiveMongoTransactionManager al archivo ReactiveMongoConfig.java:
public class ReactiveMongoConfig extends AbstractReactiveMongoConfiguration { //... ReactiveMongoTransactionManager transactionManager(ReactiveMongoDatabaseFactory dbFactory) { return new ReactiveMongoTransactionManager(dbFactory); } }
Puede definir el alcance de una transacción mediante un objeto TransactionalOperator o la anotación @Transactional. La clase TxnService muestra ambos enfoques.
Pruebe la aplicación
Ejecutar la aplicación
Para iniciar la aplicación, ejecute los siguientes comandos desde el directorio raíz del proyecto:
mvn spring-boot:run
Tras iniciar la aplicación, puede acceder a ella en http://localhost:8080. A continuación, puede usar los puntos de conexión de la API REST para crear cuentas y realizar transacciones.
Crear una cuenta
Para crear una nueva cuenta bancaria que tenga un número de cuenta de 12345, ejecute el siguiente comando en su shell:
curl --location 'localhost:8080/account' \ --header 'Content-Type: application/json' \ --data '{ "accountNum": "12345" }'
Este comando envía una solicitud POST al punto final /account para crear un nuevo documento de cuenta bancaria en la colección accounts.
Aumente el saldo de su cuenta
Para depositar dinero en la cuenta creada en el paso anterior, ejecute el siguiente comando en su shell:
curl --location 'localhost:8080/account/12345/debit' \ --header 'Content-Type: application/json' \ --data '{ "amount": 1000 }'
Este comando envía una solicitud al punto final .../debit para aumentar el valor amount del documento account correspondiente en 1000.
Transferir dinero entre cuentas
Para transferir dinero de una cuenta a otra, cree una nueva cuenta que tenga un número de cuenta de 67890:
curl --location 'localhost:8080/account' \ --header 'Content-Type: application/json' \ --data '{ "accountNum": "67890" }'
Luego, transfiera 500 dólares a esta nueva cuenta ejecutando el siguiente comando:
curl --location 'localhost:8080/account/12345/transfer' \ --header 'Content-Type: application/json' \ --data '{ "to": "67890", "amount": 500 }'
Este comando envía una solicitud al punto final .../transfer para completar la transferencia de saldo.
Recursos adicionales
Para obtener más información sobre Spring Data MongoDB, consulte la documentación de referencia de Spring Data MongoDB.
Para ver la aplicación de ejemplo completa, consulte el repositorio de GitHub mdb-spring-boot-reactive.