Overview
このガイドでは、 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)の値です。
次の表では、因果整合性のあるセッションが提供する保証について説明しています。
保証 | 説明 |
|---|---|
書込み操作の結果を読み取る | 読み取り操作は、前の書込み操作の結果を反映します。 |
単調な読み取り | 読み取り操作では、前の 読み取り操作よりも前のデータ状態を反映した結果は返されません。 |
単調書込み | 書込み操作が他の書込み操作に優先する必要がある場合、サーバーはこの書込み操作を最初に実行します。 例、 |
書込み操作の前に読み取り操作をする | 書込み操作が他の読み取り操作の後に続く必要がある場合、サーバーは最初に読み取り操作を実行します。 例、 |
Tip
このセクションで述べられた概念の詳細については、次のMongoDB Serverマニュアル エントリを参照してください。
トランザクション API
このセクションでは、 Cドライバーが提供するトランザクション API について学習できます。 トランザクションを開始する前に、mongoc_client_tインスタンスで mongoc_client_start_session() 関数を使用して mongoc_client_session_t を作成する必要があります。 その後、次のいずれかの API を使用してトランザクションを実行できます。
Convenient API
Cドライバーは、トランザクションのライフサイクルを管理するためのConvenient Transaction APIを提供します。このAPI を実装するには、mongoc_client_session_with_transaction() 関数を使用してトランザクション内でカスタムコールバックを実行します。 mongoc_client_session_with_transaction() 関数は、次のタスクを実行します。
トランザクションを開始する
操作の結果が次のような場合に、トランザクションを終了するか再試行することでエラーを処理します。
TransientTransactionErrorトランザクションをコミットする
このガイドの「トランザクションの例」セクションでは、このAPIを使用してトランザクションを実行する方法を示します。
Core API
あるいは、mongoc_client_session_tインスタンスで次の関数を使用すると、トランザクション ライフサイクルをより制御できます。
関数 | 説明 |
|---|---|
| Starts a new transaction, configured with the given options, on
this session. Returns false and sets the provided error if there are
invalid arguments, such as a session with a transaction already in progress. To
learn more about this function, see the startTransaction() page in the Server manual. |
| Ends the active transaction for this session. Returns false and sets the provided
error if there is no active transaction for the session or the
transaction has been committed or ended. To learn more about
this function, see the abortTransaction() page in the Server manual. |
| Commits the active transaction for this session. Returns an
error if there is no active transaction for the session or if the
transaction was ended. To learn more about
this function, see the commitTransaction() page in the Server manual. |
| Aborts any transactions in progress and ends this session. Frees
all client resources associated with this session. |
mongoc_client_session_tプロパティを取得し、可変セッション プロパティを変更する関数の詳細については、 APIドキュメントを参照してください。
トランザクションの例
この例では、金融トランザクションのためにsample_bankデータベースのコレクション内のデータを変更するコールバック関数を定義します。 このコードは、次のアクションを実行します。
コールバック関数を定義します。この関数は、
mongoc_client_session_tインスタンスをパラメータとして受け取ります。ターゲット コレクションにアクセスするための
mongoc_collection_tインスタンスを作成します。アカウント間で転送されるアカウント番号と金額を指定します。
送金を反映するようにカスタマーの残高を更新します。
トランザクションの受信をタイムスタンプとともに記録します。
トランザクションが正常にコミットされた場合は、メッセージを出力します。
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), "}"); if (!mongoc_collection_update_one(checking, filter, update_decrement, NULL, NULL, &error)) { fprintf(stderr, "Failed to update checking account: %s\n", error.message); return false; } if (!mongoc_collection_update_one(savings, filter, update_increment, NULL, NULL, &error)) { fprintf(stderr, "Failed to update savings account: %s\n", error.message); 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, NULL, NULL, &error)) { fprintf(stderr, "Failed to insert receipt: %s\n", error.message); return false; } 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; }
次に、次のコードを実行してトランザクションを実行します。 このコードは、次のアクションを完了します。
mongoc_client_start_session()関数を使用してクライアントからセッションを作成します。セッションとコールバックをパラメータとして渡して、トランザクションを管理するために
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 つのトランザクション内で複数の名前空間に対して書込み操作を実行できます。 詳細については、 一括書込み操作 のガイドをご覧ください。
詳細情報
このガイドで言及されている概念の詳細については、 MongoDB Serverマニュアルの次のページ を参照してください。
ACID compliance の詳細については、 「 データベース管理システムの ACID プロパティとは 」を参照してください。 MongoDB Webサイトの記事。
API ドキュメント
このガイドで説明した型や関数の詳細については、次のAPIドキュメントを参照してください。