개요
Spring Boot는 프로덕션용 애플리케이션 개발을 간소화하는 오픈 소스 Java 프레임워크 입니다.Spring Data MongoDB 와 결합된 이 프레임워크 MongoDB 데이터베이스와 효율적으로 상호 작용 수 있는 방법을 제공합니다.
이 튜토리얼에서는 Spring Data MongoDB 사용하여 MongoDB database 에서 작업을 수행하는 반응형 Spring Boot 애플리케이션 빌드 방법을 보여줍니다. 이 샘플 현금 잔액 애플리케이션 사용하여 다음 작업을 수행하는 REST API를 호출할 수 있습니다.
계정 만들기 또는 가져오기
한 계정에서 또는 두 계정 간에 거래 수행
Spring Data MongoDB
Spring Data MongoDB MongoDB 에 대한 리포지토리 지원 제공하여 데이터베이스 와 상호 작용 하는 두 가지 프라이머리 방법을 제공합니다.
ReactiveMongoRepository: 일반적인 데이터베이스 작업에 대한 액세스 제공하는 상위 수준 추상화입니다.
ReactiveMongoTemplate: MongoDB 작업 및 쿼리 구성에 대한 더 많은 제어를 제공하는 하위 수준 추상화입니다.
다중 문서 ACID 트랜잭션
MongoDB 다중 문서 ACID 트랜잭션을 지원하므로 원자성, 일관성, 격리 및 내구성 보장 충족하는 여러 작업을 수행할 수 있습니다. Spring Data MongoDB @Transactional 주석 또는 TransactionalOperator 클래스를 통해 트랜잭션에 대한 내장 지원 제공합니다. 이 튜토리얼의 샘플 애플리케이션 데이터베이스 작업의 원자성을 보장하기 위해 트랜잭션 지원 구성합니다.
튜토리얼
이 튜토리얼에서는 간소화된 현금 잔액 시스템을 구현하는 예시 애플리케이션 다운로드 방법을 보여줍니다. 이 애플리케이션 사용하면 은행 계좌 잔액을 생성, 조회 및 업데이트 할 수 있습니다. 전체 애플리케이션 보려면 mdb-spring-boot-reactive GitHub 리포지토리 참조하세요.
튜토리얼을 완료하여 다음 조치를 수행하는 방법을 학습 .
예시 Spring Boot 애플리케이션 다운로드
MongoDB 에 연결하도록 애플리케이션 구성
애플리케이션 구조 및 주요 구성 요소 이해
애플리케이션을 실행합니다.
은행 계좌를 생성하고 트랜잭션을 수행하기 위해 POST 요청을 보냅니다.
연결 다운로드 및 구성
애플리케이션 구조 이해
계정 관리 엔드포인트 검토
AccountController.java 파일 계정을 만들고 가져오기 위한 REST API 엔드포인트가 포함되어 있습니다. 이 파일 txn-demo.accounts 컬렉션 에 문서 삽입하는 POST 메서드 엔드포인트와 accountNum 값을 기반으로 문서 찾는 GET 메서드 엔드포인트를 정의합니다. 다음 코드는 이러한 메서드를 보여줍니다.
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())); } //... }
각 엔드포인트는 기본 Java Reactive Streams 운전자 에서 추상화 역할을 하는 ReactiveMongoRepository 인터페이스인 AccountRepository에서 Mono<Account> 유형을 반환합니다.
잔액 트랜잭션 엔드포인트 검토
AccountController 클래스에는 다음 트랜잭션 엔드포인트도 포함되어 있습니다.
계정 잔액에 추가되는
.../debit엔드포인트계정 잔액에서 차감하는
.../credit엔드포인트한 계정에서 다른 계정으로 전송을 수행하는
.../transfer엔드포인트
이러한 엔드포인트에는 다음과 같은 정의가 있습니다.
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); } //... }
하나의 TxnEntry 객체 단일 계정에 대한 변경 사항을 나타내며, Txn 는 하나 또는 여러 개의 TxnEntry 객체로 구성될 수 있습니다. 샘플 코드에서 차변 및 크레딧 엔드포인트는 하나의 새 TxnEntry 객체 생성하고 전송 엔드포인트는 두 개의 TxnEntry 객체를 생성합니다.
사용자 지정 쿼리 메서드 검토
AccountRepository 인터페이스는 ReactiveMongoRepository 을 확장하고 다음 쿼리 메서드를 정의합니다.
public interface AccountRepository extends ReactiveMongoRepository<Account, String> { Mono<Account> findByAccountNum(String accountNum); Mono<Long> findAndIncrementBalanceByAccountNum(String accountNum, double increment); }
이 코드는 MongoDB 쿼리 때 메서드 인수로 동적으로 대체되는 자리 표시자를 사용할 수 있도록 하는 다음 주석을 사용합니다.
@Query:findByAccountNum()메서드에 주석을 달고 문서를 찾기 위한 쿼리 기준을 지정합니다.?0자리 표시자는accountNum매개 변수 값으로 대체됩니다.@Update:findAndIncrementBalanceByAccountNum()메서드에 주석을 달고 일치하는 문서에 수행할 업데이트 작업을 지정합니다.?1자리 표시자가increment매개 변수 값으로 대체되어 MongoDB의$inc연산자 사용하여 잔액을 늘릴 수 있습니다.
참고
이전 단계에서 설명한 POST 엔드포인트는 메서드를 사용하지만 accountRepository.save() 이 메서드를 정의할 필요는 없습니다.save() 메서드 및 기타 많은 기본 메서드는 의 상속 체인에 있는 인터페이스에 의해 이미 선언되어 있습니다.ReactiveMongoRepository
트랜잭션 서비스 이해
TxnService 클래스는 트랜잭션 실행을 처리합니다. 이 클래스에는 다음 코드가 포함되어 있습니다.
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(/*...*/); } }
TxnService 클래스에는 다음 메서드가 포함되어 있습니다.
saveTransaction():Txn문서transactions컬렉션 에 저장합니다.executeTxn():updateBalances()메서드를 호출한 다음Txn문서 에서 트랜잭션 상태를 업데이트합니다.updateBalances(): 각TxnEntry를 반복하고 각account문서 에 해당하는 업데이트를 수행합니다.
트랜잭션 템플릿 검토
이전 단계에서 설명한 saveTransaction() 및 executeTxn() 메서드는 모두 TxnTemplate 클래스에 정의된 메서드를 사용합니다. 이러한 메서드에는 다음과 같은 정의가 있습니다.
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); } //... }
이러한 메서드는 ReactiveMongoTemplate를 사용하여 MongoDB 와 상호 작용 .
다중 문서 트랜잭션 구성
계정 간에 돈을 이체할 때 다중 문서 트랜잭션 사용할 수 있습니다. 두 계정에 대한 업데이트는 원자적이어야 하며 트랜잭션은 데이터 원자성을 보장합니다.
Spring의 트랜잭션 지원 액세스 위해 샘플 애플리케이션 ReactiveMongoConfig.java 파일 에 ReactiveMongoTransactionManager 빈을 추가합니다.
public class ReactiveMongoConfig extends AbstractReactiveMongoConfiguration { //... ReactiveMongoTransactionManager transactionManager(ReactiveMongoDatabaseFactory dbFactory) { return new ReactiveMongoTransactionManager(dbFactory); } }
TransactionalOperator 객체 또는 @Transactional 주석을 사용하여 트랜잭션 의 범위를 정의할 수 있습니다. TxnService 클래스는 두 가지 접근 방식을 모두 보여줍니다.
애플리케이션 테스트
계정 간 송금
한 계정에서 다른 계정으로 돈을 이체하려면 계정 번호가 67890인 새 계정을 만듭니다.
curl --location 'localhost:8080/account' \ --header 'Content-Type: application/json' \ --data '{ "accountNum": "67890" }'
그런 다음 다음 명령을 실행 하여 500 달러를 이 새 계정으로 이체합니다.
curl --location 'localhost:8080/account/12345/transfer' \ --header 'Content-Type: application/json' \ --data '{ "to": "67890", "amount": 500 }'
이 명령은 잔액 이체를 완료하기 위해 .../transfer 엔드포인트에 요청 보냅니다.
추가 리소스
Spring Data MongoDB 에 대해 자세히 학습 Spring Data MongoDB 참고 문서를 참조하세요.
전체 예시 애플리케이션 보려면 mdb-spring-boot-reactive GitHub 리포지토리 참조하세요.