Overview
このガイドでは、 MongoDB C++ドライバーを使用して トランザクション を実行する方法を学習できます。トランザクション を使用すると、トランザクションがコミットされるまでデータを変更しない一連の操作を実行できます。 トランザクション内のいずれかの操作でエラーが返された場合、ドライバーはトランザクションをキャンセルし、変更が反映される前にすべてのデータ変更を破棄します。
MongoDBでは、トランザクションは論理 セッション 内で実行されます。セッションは 、順番に実行されるよう関連付けられた読み取り操作または書き込み操作のグループです。 セッションにより、 ACID準拠のトランザクション内の操作のグループに対して因果整合性が有効になります。このトランザクションは、アトミック性、整合性、分離、耐久性に対する期待を満たすトランザクションです。MongoDBは、トランザクション操作で予期せぬエラーが発生した場合でも、その操作に関わるデータの一貫性が保たれることを保証します。
注意
C++ドライバーは、単一のトランザクション内での並列操作の実行中をサポートしていません。
C++ドライバーを使用すると、 mongocxx::clientインスタンスから新しいセッションを作成できます。 その後、結果の mongocxx::client_sessionインスタンスを使用してトランザクションを実行できます。 毎回新しいクライアントをインスタンス化するのではなく、クライアントを複数のセッションやトランザクションで再利用することを推奨します。
警告
mongocxx::client_session は、それを作成した mongocxx::client でのみ使用します。 client_session と別の client を使用すると、操作エラーが発生します。
重要
mongocxx::client のインスタンスはスレッドセーフではありません。 各 mongoxcc::clientインスタンスとその子インスタンス(mongocxx::client_session を含む)は、一度に 1 つのスレッドで使用する必要があります。 詳しくは、「 スレッドとフォークの安全性ガイド 」を参照してください。
因果整合性
MongoDB は特定のクライアントセッションで因果整合性を有効にします。因果整合性モデルは、分散システム内でセッション内の操作が因果順序で実行されることを保証します。クライアントは、因果関係、または操作間の依存関係と整合性のある結果を観察します。例、ある操作が別の操作の結果に論理的に依存する一連の操作を実行すると、後続のすべての読み取りは 依存関係を反映します。
因果整合性を保証するには、クライアントセッションが次の要件を満たす必要があります。
セッションを開始するとき、ドライバーは 因果整合性 オプションを有効にする必要があります。このオプションはデフォルトで有効になっています。
操作は 1 つのスレッド上の 1 つのセッションで実行する必要があります。それ以外の場合、セッションまたはスレッドは optime とクラスター時間の値を相互に通信する必要があります。 これらの値を通信する 2 つのセッションの例については、 MongoDB Serverマニュアルの 因果整合性の例 を参照してください。
mongocxx::read_concern::level::k_majorityの読み取り保証 (read concern)を使用する必要があります。mongocxx::write_concern::level::k_majorityの書込み保証 (write concern)を使用する必要があります。これは、デフォルトの書込み保証 (write concern)の値です。
次の表では、因果整合性のあるセッションが提供する保証について説明しています。
保証 | 説明 |
|---|---|
書込み操作の結果を読み取る | 読み取り操作は、前の書込み操作の結果を反映します。 |
単調な読み取り | 読み取り操作では、前の 読み取り操作よりも前のデータ状態を反映した結果は返されません。 |
単調書込み | 書込み操作が他の書込み操作に優先する必要がある場合、サーバーはこの書込み操作を最初に実行します。 例、 |
書込み操作の前に読み取り操作をする | 書込み操作が他の読み取り操作の後に続く必要がある場合、サーバーは最初に読み取り操作を実行します。 例、 |
Tip
このセクションで述べられた概念の詳細については、次のMongoDB Serverマニュアル エントリを参照してください。
トランザクション API
MongoDB C++ドライバーは、トランザクション ライフを管理するための Callback APIと Core API を提供します。 トランザクションを開始する前に、start_session() メソッドを呼び出して mongocxx::client_session をインスタンス化する必要があります。 その後、次のいずれかの API を使用してトランザクションを実行できます。
Callback API : トランザクションのライフサイクルを管理し、エラー処理ロジックを自動的に組み込む高レベルのAPI 。
Core API : トランザクションのライフサイクルを管理し、カスタムエラー処理ロジックを実装できる低レベルのAPI 。
Tip
エラー処理の詳細については、 MongoDB Serverマニュアルの「 トランザクション エラー処理 」セクションを参照してください。
Callback API
Callback API を使用して、 MongoDB C++ドライバーがトランザクションのライフサイクルを管理できるようにします。 このAPI を実装するには、mongocxx::client_session で with_transaction() メソッドを呼び出し、実行する操作のシーケンスを指定するコールバック関数で渡します。 with_transaction() メソッドはトランザクションを開始し、コールバック関数を実行し、エラーが発生した場合はトランザクションをコミットするか、トランザクションを終了します。 トランザクションで TransientTransactionError または UnknownTransactionCommitResult エラーが発生した場合、with_transaction() メソッドはトランザクションを再実行します。
次のコードでは、コールバックAPI を使用してトランザクションを実行し、sample_mflixデータベースの movies コレクションと comments コレクションにドキュメントを挿入します。 このコードは、次のアクションを実行します。
start_session()メソッドを使用してクライアントからセッションを開始します。トランザクション中に実行する操作を指定するコールバック関数を定義します。
コールコールバック関数とオプションオブジェクトを引数として渡して、トランザクションを管理するために
with_transaction()メソッドを呼び出します。
// Establish a connection to the MongoDB deployment mongocxx::instance instance{}; mongocxx::client client(mongocxx::uri{"<connectionString>"}); // Define database and collection variables auto db = client["sample_mflix"]; auto movies_collection = db["movies"]; auto comments_collection = db["comments"]; // Define a callback specifying the sequence of operations to perform during the transaction mongocxx::client_session::with_transaction_cb callback = [&](mongocxx::client_session* session) { // Important:: You must pass the session to the operations. movies_collection.insert_one(*session, make_document(kvp("title", "Parasite"))); comments_collection.insert_one(*session, make_document(kvp("name", "Anjali Patel"), kvp("text", "This is my new favorite movie!"))); }; // Define an options instance to explicitly set the write concern for the transaction operations mongocxx::options::transaction opts; mongocxx::write_concern wc; wc.acknowledge_level(mongocxx::write_concern::level::k_majority); opts.write_concern(wc); // Start a client session auto session = client.start_session(); try { // Start a transaction, execute the operations in the callback function, and commit the results session.with_transaction(callback, opts); } catch (const mongocxx::exception& e) { std::cout << "An exception occurred: " << e.what() << std::endl; return EXIT_FAILURE; } return EXIT_SUCCESS;
Core API
Core API を使用して、トランザクションのライフサイクルを管理します。 このAPI を実装するには、トランザクションを開始し、アクティブなトランザクションをコミットし、エラーが発生した場合はトランザクションを終了するために、mongocxx::client_session インターフェースのメソッドを明示的に呼び出す必要があります。 Core API にはエラー処理ロジックが自動的に組み込まれておらず、代わりに TransientTransactionError や UnknownTransactionCommitResult などのエラーのカスタム処理ロジックを実装できます。
次の表では、mongocxx::client_session インターフェースが提供する Core APIメソッドについて説明しています。
方式 | 説明 |
|---|---|
| 現在のクライアント セッションで新しいトランザクションを開始します。オプションを設定するための引数として任意の |
| 現在のクライアント セッションでアクティブなトランザクションをコミットします。 |
| 現在のクライアント セッションでアクティブなトランザクションを終了します。 |
Tip
mongocxx::client_sessionクラスには、セッション プロパティを検索および変更するメソッドも用意されています。詳細については、 APIドキュメントのmongocxx::client_sessionを参照してください。
次のコードでは Core API を使用してトランザクションを実行し、sample_mflixデータベースの movies コレクションと comments コレクションにドキュメントを挿入します。 このコードは、次のアクションを実行します。
start_session()メソッドを使用してクライアントからセッションを開始します。オプションオブジェクトを引数として渡してトランザクションを開始するための
start_transaction()メソッドを呼び出します。アクティブなセッションを各操作に渡して、
sample_mflixデータベース内のコレクションにドキュメントを挿入する操作を実行します。 ある操作でエラーが発生すると、トランザクション全体が中止されます。 エラーのラベルがTransientTransactionErrorの場合、トランザクションは再試行されます。commit_transaction()メソッドを使用してアクティブなトランザクションをコミットします。 コミットでラベルUnknownTransactionCommitResultのエラーが発生した場合、コミットは再試行されます。
// Establish a connection to the MongoDB deployment mongocxx::instance instance{}; mongocxx::client client(mongocxx::uri{"<connectionString>"}); // Runs the txn_func and retries if TransientTransactionError occurs using transaction_func = std::function<void(mongocxx::client_session& session)>; auto run_with_retry = [](transaction_func txn_func, mongocxx::client_session& session) { while (true) { try { txn_func(session); // performs transaction. break; } catch (const mongocxx::operation_exception& oe) { std::cout << "Transaction aborted. Caught exception during transaction." << std::endl; // If transient error, retry the whole transaction. if (oe.has_error_label("TransientTransactionError")) { std::cout << "TransientTransactionError, retrying transaction..." << std::endl; continue; } else { throw oe; } } } }; // Commits the active transaction and retries commit if UnknownTransactionCommitResult occurs auto commit_with_retry = [](mongocxx::client_session& session) { while (true) { try { session.commit_transaction(); // Uses write concern set at transaction start. std::cout << "Transaction committed." << std::endl; break; } catch (const mongocxx::operation_exception& oe) { // Can retry commit if (oe.has_error_label("UnknownTransactionCommitResult")) { std::cout << "UnknownTransactionCommitResult, retrying commit..." << std::endl; continue; } else { std::cout << "Error during commit..." << std::endl; throw oe; } } } }; auto txn_func = [&](mongocxx::client_session& session) { auto& client = session.client(); // Define database and collection variables auto db = client["sample_mflix"]; auto movies_collection = db["movies"]; auto comments_collection = db["comments"]; // Define an options instance to explicitly set the write concern for the transaction operations mongocxx::options::transaction opts; mongocxx::write_concern wc; wc.acknowledge_level(mongocxx::write_concern::level::k_majority); opts.write_concern(wc); session.start_transaction(opts); // Attempt to insert documents into database collections try { movies_collection.insert_one(session, make_document(kvp("title", "Parasite"))); comments_collection.insert_one(session, make_document(kvp("name", "Anjali Patel"), kvp("text", "This is my new favorite movie!"))); } catch (const mongocxx::operation_exception& oe) { std::cout << "Caught exception during transaction, aborting." << std::endl; session.abort_transaction(); throw oe; } commit_with_retry(session); }; // Start a client session auto session = client.start_session(); try { run_with_retry(txn_func, session); } catch (const mongocxx::operation_exception& oe) { // Do something with error throw oe; }
詳細情報
このガイドで説明されている概念の詳細については、 MongoDB Serverマニュアルの次のページを参照してください 。
ACIDコンプライアンスの詳細については、 MongoDBウェブサイトの「 データベース管理システムのACIDプロパティ 」ガイドを参照してください。
挿入操作の詳細については、ドキュメントの挿入ガイドを参照してください。
API ドキュメント
このガイドで説明した型やメソッドの詳細については、次の API ドキュメントを参照してください。