AI エージェント向け: ドキュメントインデックスは https://www.mongodb.com/ja-jp/docs/llms.txt で利用できます。すべてのページの markdown バージョンは、いずれかの URL パスに .md を追加することで利用できます。

チュートリアル: 書込み (write) との統合

Spring Boot は、本番環境に対応したアプリケーションの開発を簡素化するオープンソースのJavaフレームワークです。When combined with Spring Data MongoDB, this フレームワーク provides an efficient way to interact with MongoDB データベース.

このチュートリアルでは、spring Data MongoDBを使用してMongoDBデータベースで操作を実行する、リアクティブな Spring Boot アプリケーションをビルドする方法について説明します。このサンプルキャッシュ 残高アプリケーションを使用して、次のアクションを実行する REST API を呼び出すことができます。

  • アカウントを作成または取得する

  • 1 つのアカウントまたは 2 つのアカウント間でトランザクションを実行

spring Data MongoDB はMongoDBのリポジトリをサポートし、データベースを操作するための 2 つのプライマリ方法を提供します。

  • ReactiveMongoRepository: 一般的なデータベース操作へのアクセスを提供する高レベルの抽象化

  • ReactiveMongoTemplate: MongoDB の操作とクエリ構築をより制御できる低レベルの抽象化

MongoDB はマルチドキュメントACIDトランザクション をサポートしており、アトミック性、整合性、分離、耐久性保証を満たす複数の操作を実行できます。spring Data MongoDB は、@Transactional アノテーションまたは TransactionalOperatorクラスによるトランザクションの組み込みサポートを提供します。このチュートリアルのサンプルアプリケーションでは、データベース操作のアトミック性を確保するためにトランザクションをサポートするように構成されています。

MongoDBトランザクションの詳細については、 MongoDB Serverマニュアルのトランザクションを参照してください。

このチュートリアルでは、簡略化されたキャッシュ残高システムを実装する例アプリケーションをダウンロードする方法を説明します。アプリケーションを使用すると、金融アカウントの残高を作成、検索する、更新できます。完全なアプリケーションを表示するには、mdb-spring-boot-reactive GitHubリポジトリ を参照してください。

次のアクションを実行する方法については、チュートリアルを完了してください。

  • 例のSpring Bootアプリケーションをダウンロードする

  • MongoDBに接続するためのアプリケーションの構成

  • アプリケーション構造と主要なコンポーネントを理解する

  • アプリケーションを実行する

  • 金融アカウントを作成しトランザクションを実行するための POST リクエストの送信

1

このチュートリアルを開始する前に、次のコンポーネントが準備されていることを確認してください。

2

次のコマンドを実行中て、 MongoDB Developer GitHubリポジトリから例アプリケーションをクローンします。

git clone git@github.com:mongodb-developer/mdb-spring-boot-reactive.git

このリポジトリには、spring Data MongoDBを使用してMongoDBデータベースを操作する、リアクティブな SPIアプリケーションが含まれています。

3

例アプリケーションディレクトリ内の src/main/resources/application.propertiesファイルに移動します。このファイルで、次のコードに示すように、spring.data.mongodb.uriプロパティをAtlas 接続 URI に設定します。

spring.data.mongodb.uri=<connection URI>

<connection URI> プレースホルダーを Atlas 接続 URI に置き換えます。

4

ルートディレクトリから次のコマンドを実行して、アプリケーションのスキーマ検証を設定します。

mongosh "<connection URI>" --file setup.js

このコマンドは、金融アカウントの残高が 0 を下回らないようにする制約を作成します。<connection URI> プレースホルダーを Atlas 接続 URI に置き換えます。

1

AccountController.javaファイルには、アカウントを作成および取得するためのREST APIエンドポイントとなる接続されたデバイスが含まれています。このファイルは、txn-demo.accountsコレクションにドキュメントを挿入する POST メソッド エンドポイントと、その accountNum 値に基づいてドキュメントを検索する GET メソッド エンドポイントを定義します。次のコードは、これらのメソッドを示しています。

@RestControllerpublic class AccountController { //... @PostMapping("/account") public Mono<Account> createAccount(@RequestBody Account account) { return accountRepository.save(account); } @GetMapping("/account/{accountNum}") public Mono<Account> getAccount(@PathVariable String accountNum) { return accountRepository.findByAccountNum(accountNum) .switchIfEmpty(Mono.error(new AccountNotFoundException())); } //...}

各エンドポイントとなる接続されたデバイスは、AccountRepository から Mono<Account> 型を返します。これは、基礎のJava Reactive Streams ドライバーからの抽象化として機能する ReactiveMongoRepository インターフェースです。

2

AccountControllerクラスには、次のトランザクション エンドポイントとなる接続されたデバイスも含まれます。

  • アカウント残高に追加する .../debit エンドポイントとなる接続されたデバイス

  • アカウント残高から減算する .../credit エンドポイントとなる接続されたデバイス

  • あるアカウントから別のアカウントへの転送を実行する .../transfer エンドポイントとなる接続されたデバイス

これらのエンドポイントとなる接続されたデバイスには、次の定義があります。

@RestControllerpublic class AccountController { //... @PostMapping("/account/{accountNum}/debit") public Mono<Txn> debitAccount(@PathVariable String accountNum, @RequestBody Map<String, Object> requestBody) { //... txn.addEntry(new TxnEntry(accountNum, amount)); return txnService.saveTransaction(txn).flatMap(txnService::executeTxn); } @PostMapping("/account/{accountNum}/credit") public Mono<Txn> creditAccount(@PathVariable String accountNum, @RequestBody Map<String, Object> requestBody) { //... txn.addEntry(new TxnEntry(accountNum, -amount)); return txnService.saveTransaction(txn).flatMap(txnService::executeTxn); } @PostMapping("/account/{from}/transfer") public Mono<Txn> transfer(@PathVariable String from, @RequestBody 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 オブジェクトが作成されます。

3

AccountRepository インターフェースは ReactiveMongoRepository を拡張し、次のクエリメソッドを定義します。

public interface AccountRepository extends ReactiveMongoRepository<Account, String> { @Query("{accountNum:'?0'}") Mono<Account> findByAccountNum(String accountNum); @Update("{'$inc':{'balance': ?1}}") Mono<Long> findAndIncrementBalanceByAccountNum(String accountNum, double increment);}

コードは次の注釈を使用し、メソッド引数で動的に置き換えられるMongoDB をクエリするときにプレースホルダーを使用できます。

  • @Query: findByAccountNum() メソッドに注釈を付け、ドキュメントを検索するためのクエリ条件を指定します。?0 プレースホルダーは accountNum パラメータ値で置き換えられます。

  • @Update: findAndIncrementBalanceByAccountNum() メソッドに注釈を付け、一致するドキュメントに対して実行する更新操作を指定します。MongoDB の $inc 演算子を使用してバランスを増やすために、?1 プレースホルダーは increment パラメーター値に置き換えられます。

注意

前の手順で説明した POST エンドポイントでは accountRepository.save() メソッドが使用されていますが、このメソッドを定義する必要はありません。save() メソッドおよびその他の多くの基本メソッドは、ReactiveMongoRepository の継承チェーン内のインターフェースによってすでに宣言されています。

4

TxnServiceクラスはトランザクションの実行を取り扱います。このクラスには、次のコードが含まれています。

@Servicepublic 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ドキュメントに対応する更新を行います

5

前の手順で説明した saveTransaction() メソッドと executeTxn() メソッドはどちらも、TxnTemplateクラスで定義されたメソッドを使用します。これらのメソッドには、次の定義があります。

@Servicepublic 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とやりとりします。

6

アカウント間で送金を転送する場合、マルチドキュメントトランザクションを使用できます。2 つのアカウントにわたる更新は不可分である必要があり、トランザクションはデータの不可分性を確保します。

spring のトランザクション サポートにアクセスするために、サンプルアプリケーションはReactiveMongoTransactionManager bean を ReactiveMongoConfig.javaファイルに追加します。

@Configurationpublic class ReactiveMongoConfig extends AbstractReactiveMongoConfiguration { //... @Bean ReactiveMongoTransactionManager transactionManager(ReactiveMongoDatabaseFactory dbFactory) { return new ReactiveMongoTransactionManager(dbFactory); }}

TransactionalOperatorオブジェクトまたは @Transactional アノテーションを使用して、トランザクションのスコープを定義できます。TxnServiceクラスは両方のアプローチを示しています。

Tip

Spring Data トランザクション

spring Data MongoDBのトランザクションとセッションの詳細については、spring Data ドキュメントの「 セッションとトランザクション 」を参照してください。

1

アプリケーションを起動するには、プロジェクトの ルートディレクトリから次のコマンドを実行します。

mvn spring-boot:run

アプリケーションの起動後は、http://localhost:8080 でアクセスできます。その後、 REST APIエンドポイントとなる接続されたデバイスを使用してアカウントを作成し、トランザクションを実行できます。

2

アカウント番号が 12345 である新しい金融アカウントを作成するには、 シェルで次のコマンドを実行します。

curl --location 'localhost:8080/account' \--header 'Content-Type: application/json' \--data '{ "accountNum": "12345"}'

このコマンドは、/account エンドポイントとなる接続されたデバイスに POSTリクエストを送信し、accountsコレクションに新しい金融アカウントドキュメントを作成します。

3

前のステップで作成されたアカウントにデプロイするには、 シェルで次のコマンドを実行します。

curl --location 'localhost:8080/account/12345/debit' \--header 'Content-Type: application/json' \--data '{ "amount": 1000}'

このコマンドは、対応する accountドキュメントの amount の値を 1000 ずつ増やすためのリクエストを .../debit エンドポイントとなる接続されたデバイスに送信します。

4

あるアカウントから別のアカウントに送金するには、アカウント番号が 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リポジトリ を参照してください。