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

トランザクション

このガイドでは、 Cドライバーを使用して トランザクション を実行する方法を学習できます。トランザクションを使用すると、トランザクション全体がコミットされた場合にのみ、データを変更する一連の操作を実行できます。 トランザクション内のいずれかの操作が成功しない場合、ライブラリはトランザクションを停止し、変更が反映される前にすべてのデータ変更を破棄します。 この特徴は アトミック性と 呼ばれます。

MongoDB では、トランザクションは論理セッション内で実行されます。 セッションは 、順番に実行されるよう関連付けられた読み取り操作または書き込み操作のグループです。 セッションにより、一連の操作に対する因果整合性が有効になり、 ACID 準拠のトランザクション(不可分性、整合性、分離、耐久性の期待を満たすトランザクション)内で操作を実行できるようになります。 MongoDBは、トランザクション操作で予期せぬエラーが発生した場合でも、その操作に関わるデータの一貫性が保たれることを保証します。

Cドライバーを使用すると、mongoc_client_tインスタンスから新しいセッションを作成できます。 その後、結果の mongoc_client_session_tインスタンスを使用してトランザクションを実行できます。

警告

mongoc_client_session_t は、それを作成した mongoc_client_t(または関連付けられたmongoc_database_t または mongoc_collection_t)でのみ使用します。mongoc_client_session_t と、異なる mongoc_client_t を使用すると、操作エラーが発生します。

MongoDB は特定のクライアントセッションで因果整合性を有効にします。因果整合性モデルは、分散システム内でセッション内の操作が因果順序で実行されることを保証します。クライアントは、因果関係、または操作間の依存関係と整合性のある結果を観察します。例、ある操作が別の操作の結果に論理的に依存する一連の操作を実行すると、後続のすべての読み取りは 依存関係を反映します。

因果整合性を保証するには、クライアントセッションが次の要件を満たす必要があります。

  • セッションを開始するとき、ドライバーは 因果整合性 オプションを有効にする必要があります。このオプションはデフォルトで有効になっています。

  • 操作は 1 つのスレッド上の 1 つのセッションで実行する必要があります。それ以外の場合、セッションまたはスレッドは optime とクラスター時間の値を相互に通信する必要があります。 これらの値を通信する 2 つのセッションの例については、 MongoDB Serverマニュアルの 因果整合性の例 を参照してください。

  • MONGOC_READ_CONCERN_LEVEL_MAJORITY の読み取り保証 (read concern)を使用する必要があります。

  • MONGOC_WRITE_CONCERN_W_MAJORITY の書込み保証 (write concern)を使用する必要があります。これは、デフォルトの書込み保証 (write concern)の値です。

次の表では、因果整合性のあるセッションが提供する保証について説明しています。

保証
説明

書込み操作の結果を読み取る

読み取り操作は、前の書込み操作の結果を反映します。

単調な読み取り

読み取り操作では、前の 読み取り操作よりも前のデータ状態を反映した結果は返されません。

単調書込み

書込み操作が他の書込み操作に優先する必要がある場合、サーバーはこの書込み操作を最初に実行します。

例、mongoc_collection_insert_one() を呼び出してドキュメントを挿入し、mongoc_collection_update_one() を呼び出して挿入されたドキュメント を変更すると、サーバーは最初に挿入操作を実行します。

書込み操作の前に読み取り操作をする

書込み操作が他の読み取り操作の後に続く必要がある場合、サーバーは最初に読み取り操作を実行します。

例、mongoc_collection_find_with_opts() を呼び出してドキュメントを取得し、mongoc_collection_delete_one() を呼び出して取得されたドキュメントを削除すると、サーバーは最初に検索操作を実行します。

Tip

このセクションで述べられた概念の詳細については、次のMongoDB Serverマニュアル エントリを参照してください。

このセクションでは、 Cドライバーが提供するトランザクション API について学習できます。 トランザクションを開始する前に、mongoc_client_tインスタンスで mongoc_client_start_session() 関数を使用して mongoc_client_session_t を作成する必要があります。 その後、次のいずれかの API を使用してトランザクションを実行できます。

Cドライバーは、トランザクションのライフサイクルを管理するためのConvenient Transaction APIを提供します。このAPI を実装するには、mongoc_client_session_with_transaction() 関数を使用してトランザクション内でカスタムコールバックを実行します。 mongoc_client_session_with_transaction() 関数は、次のタスクを実行します。

  • トランザクションを開始する

  • 操作の結果が次のような場合に、トランザクションを終了するか再試行することでエラーを処理します。 TransientTransactionError

  • トランザクションをコミットする

このガイドの「トランザクションの例」セクションでは、このAPIを使用してトランザクションを実行する方法を示します。

あるいは、mongoc_client_session_tインスタンスで次の関数を使用すると、トランザクション ライフサイクルをより制御できます。

関数
説明

mongoc_client_session_start_transaction()

このセッションで、指定されたオプションで構成された新しいトランザクションを開始します。トランザクションが既に進行中のセッションなど、引数が無効な場合はfalseを返し、指定されたエラーを設定します。この関数の詳細については、サーバー マニュアルの startTransaction() ページを参照してください。

mongoc_client_session_abort_transaction()

このセッションのアクティブなトランザクションを終了します。セッションにアクティブなトランザクションがない場合、またはトランザクションがコミットまたは終了している場合は、falseを返し、提供されたエラーを設定します。この関数の詳細については、サーバー マニュアルの abortTransaction() ページを参照してください。

mongoc_client_session_commit_transaction()

このセッションのアクティブなトランザクションをコミットします。セッションにアクティブなトランザクションがない場合、またはトランザクションが終了した場合はエラーを返します。この関数の詳細については、サーバー マニュアルの commitTransaction() ページを参照してください。

mongoc_client_session_destroy()

進行中のトランザクションを中止し、このセッションを終了します。このセッションに関連するすべてのクライアント リソースを解放します。

mongoc_client_session_tプロパティを取得し、可変セッション プロパティを変更する関数の詳細については、 APIドキュメントを参照してください。

この例では、金融トランザクションのためにsample_bankデータベースのコレクション内のデータを変更するコールバック関数を定義します。 このコードは、次のアクションを実行します。

  1. コールバック関数を定義します。この関数は、 mongoc_client_session_tインスタンスをパラメータとして受け取ります。

  2. ターゲット コレクションにアクセスするためのmongoc_collection_tインスタンスを作成します。

  3. アカウント間で転送されるアカウント番号と金額を指定します。

  4. 送金を反映するようにカスタマーの残高を更新します。

  5. トランザクションの受信をタイムスタンプとともに記録します。

  6. トランザクションが正常にコミットされた場合は、メッセージを出力します。

bool
transaction_callback(mongoc_client_session_t *session, void *ctx, bson_t **reply,
bson_error_t *error)
{
BSON_UNUSED(ctx);
BSON_UNUSED(reply);
mongoc_client_t *client = mongoc_client_session_get_client(session);
mongoc_collection_t *checking = mongoc_client_get_collection(client, "sample_bank", "checking");
mongoc_collection_t *savings = mongoc_client_get_collection(client, "sample_bank", "savings");
mongoc_collection_t *receipts = mongoc_client_get_collection(client, "sample_bank", "receipts");
const char *account_id = "123456";
int transfer_amount = 1000;
bson_t *filter = BCON_NEW("account_id", BCON_UTF8(account_id));
bson_t *update_decrement = BCON_NEW("$inc", "{", "balance", BCON_INT32(-transfer_amount), "}");
bson_t *update_increment = BCON_NEW("$inc", "{", "balance", BCON_INT32(transfer_amount), "}");
bson_t *opts = bson_new();
BSON_ASSERT(mongoc_client_session_append(session, opts, error));
if (!mongoc_collection_update_one(checking, filter, update_decrement, opts, NULL, error)) {
fprintf(stderr, "Failed to update checking account: %s\n", error->message);
bson_destroy(opts);
return false;
}
if (!mongoc_collection_update_one(savings, filter, update_increment, opts, NULL, error)) {
fprintf(stderr, "Failed to update savings account: %s\n", error->message);
bson_destroy(opts);
return false;
}
bson_t *receipt = BCON_NEW("account_id", BCON_UTF8(account_id),
"amount", BCON_INT32(transfer_amount),
"timestamp", BCON_DATE_TIME(bson_get_monotonic_time()));
if (!mongoc_collection_insert_one(receipts, receipt, opts, NULL, error)) {
fprintf(stderr, "Failed to insert receipt: %s\n", error->message);
bson_destroy(opts);
return false;
}
bson_destroy(opts);
mongoc_collection_destroy(checking);
mongoc_collection_destroy(savings);
mongoc_collection_destroy(receipts);
bson_destroy(filter);
bson_destroy(update_decrement);
bson_destroy(update_increment);
bson_destroy(receipt);
printf("Transaction successful!");
return true;
}

次に、次のコードを実行してトランザクションを実行します。 このコードは、次のアクションを完了します。

  1. mongoc_client_start_session() 関数を使用してクライアントからセッションを作成します。

  2. セッションとコールバックをパラメータとして渡して、トランザクションを管理するためにmongoc_client_session_with_transaction()関数を呼び出します。

mongoc_client_session_t *session = mongoc_client_start_session(client, NULL, NULL);
if (!session) {
fprintf(stderr, "Failed to start session\n");
mongoc_client_destroy(client);
return EXIT_FAILURE;
}
bool result =
mongoc_client_session_with_transaction(session,
(mongoc_client_session_with_transaction_cb_t) transaction_callback,
NULL, NULL, NULL, &error);
if (!result) {
fprintf(stderr, "Transaction error: %s\n", error.message);
}
mongoc_client_session_destroy(session);
mongoc_client_destroy(client);
mongoc_cleanup();
Transaction successful!

注意

並列操作はサポートされていません

Cドライバーは、単一のトランザクション内での並列操作の実行中をサポートしていません。

MongoDB Server v8.0 以降を使用している場合は、一括書込み操作を使用して、1 つのトランザクション内で複数の名前空間に対して書込み操作を実行できます。詳細については、一括書込み (write) 操作のガイドを参照してください。

このガイドで言及されている概念の詳細については、 MongoDB Serverマニュアルの次のページ を参照してください。

ACID compliance の詳細については、 「 データベース管理システムの ACID プロパティとは 」を参照してください。 MongoDB Webサイトの記事。

このガイドで説明した型や関数の詳細については、次のAPIドキュメントを参照してください。