Overview
SPI は、本番環境に対応したアプリケーションの開発を簡素化するオープンソースのJavaフレームワークです。 spring Data MongoDBと組み合わせると、このフレームワークはMongoDBデータベースを操作する効率的な方法を提供します。
このチュートリアルでは、spring Data MongoDBを使用してMongoDBデータベースで操作を実行する、リアクティブな SPIアプリケーションを構築する方法について説明します。このサンプルキャッシュ 残高アプリケーションを使用して、次のアクションを実行する REST API を呼び出すことができます。
アカウントを作成または取得する
1 つのアカウントまたは 2 つのアカウント間でトランザクションを実行
Spring Data MongoDB
spring Data MongoDB はMongoDBのリポジトリをサポートし、データベースを操作するための 2 つのプライマリ方法を提供します。
ReactiveMongoRepository: 一般的なデータベース操作へのアクセスを提供する高レベルの抽象化
ReactiveMongoTemplate: MongoDB の操作とクエリ構築をより制御できる低レベルの抽象化
マルチドキュメントACIDトランザクション
MongoDB はマルチドキュメントACIDトランザクション をサポートしており、アトミック性、整合性、分離、耐久性保証を満たす複数の操作を実行できます。 spring Data MongoDB は、 @Transactional アノテーションまたは TransactionalOperatorクラスによるトランザクションの組み込みサポートを提供します。このチュートリアルのサンプルアプリケーションでは、データベース操作のアトミック性を確保するためにトランザクションをサポートするように構成されています。
MongoDBトランザクションの詳細については、 MongoDB Serverマニュアルの「 トランザクション 」を参照してください。
Tutorial
このチュートリアルでは、簡略化されたキャッシュ残高システムを実装する例アプリケーションをダウンロードする方法を説明します。アプリケーションを使用すると、金融アカウントの残高を作成、検索、更新できます。完全なアプリケーションを表示するには、 mdb-spring-boot-reactive GitHubリポジトリ を参照してください。
次のアクションを実行する方法については、チュートリアルを完了してください。
例をダウンロード
MongoDBに接続するためのアプリケーションの構成
アプリケーション構造と主要なコンポーネントを理解する
アプリケーションを実行する
金融アカウントを作成しトランザクションを実行するための POST リクエストの送信
接続のダウンロードと構成
前提条件を確認します
このチュートリアルを開始する前に、次のコンポーネントが準備されていることを確認してください。
構成されたクラスターを持つMongoDB Atlasアカウント。クラスターの作成方法については、 「MongoDBスタートガイド」をご覧ください。
Java21 以降。
Maven.3 5以降。
アプリケーション構造の理解
アカウントマネジメントのエンドポイントの確認
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())); } //... }
各エンドポイントは、AccountRepository から Mono<Account> 型を返します。これは、基礎となるJava Reactive Streams ドライバーからの抽象化として機能する ReactiveMongoRepository インターフェースです。
残高トランザクションのエンドポイントの確認
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); } //... }
1 つの TxnEntryオブジェクトは1 つのアカウントに対する変更を表し、Txn は 1 つまたは複数の TxnEntry オブジェクトで構成できます。サンプルコードでは、デビットとクレジットのエンドポイントにより新しい TxnEntryオブジェクトが1 つ作成され、転送エンドポイントにより 2 つの 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()メソッドに注釈を付け、一致するドキュメントに対して実行するアップデート操作を指定します。 MongoDB の$inc演算子を使用してバランスを増やすために、?1プレースホルダーはincrementパラメーター値に置き換えられます。
トランザクション サービスを理解する
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とやりとりします。
マルチドキュメントトランザクション の構成
アカウント間で送金を転送する場合、マルチドキュメントトランザクションを使用できます。 2 つのアカウントにわたる更新は不可分である必要があり、トランザクションはデータの不可分性を確保します。
spring のトランザクション サポートにアクセスするために、サンプルアプリケーションはReactiveMongoTransactionManager bean を ReactiveMongoConfig.javaファイルに追加します。
public class ReactiveMongoConfig extends AbstractReactiveMongoConfiguration { //... ReactiveMongoTransactionManager transactionManager(ReactiveMongoDatabaseFactory dbFactory) { return new ReactiveMongoTransactionManager(dbFactory); } }
TransactionalOperatorオブジェクトまたは @Transactional アノテーションを使用して、トランザクションのスコープを定義できます。 TxnServiceクラスは両方のアプローチを示しています。
Tip
spring Data Transactions
spring Data MongoDBのトランザクションとセッションの詳細については、spring Data ドキュメントの「 セッションとトランザクション 」を参照してください。
アプリケーションをテストする
アカウント間での送金
あるアカウントから別のアカウントに送金するには、アカウント番号が 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リポジトリ を参照してください。