MongoDBでは、1 つのドキュメントに対する操作は不可分です。単一ドキュメント構造内でのデータ間の関係をキャプチャするには、複数のドキュメントとコレクションにわたる正規化プロセスを経る代わりに埋め込みドキュメントと配列を利用できるため、マルチドキュメントトランザクションは多数の実用的なユースケースでは不要になります。
複数のドキュメントに対する操作のアトミック性が必要な状況では、 MongoDB はトランザクションをサポートします。複数の操作、コレクション、データベース、ドキュメント、シャードにわたってトランザクションを使用できます。
トランザクション API
言語セレクターを使用して、次の例の言語を設定します。
Tip
の例については、mongosh、mongosh 例。を参照してください。
トランザクションと不可分性
MongoDB は(単一または複数のコレクション内の)複数のドキュメントへの読み取りと書込みにアトミック性を必要とする状況で、レプリカセットやシャーディングされたクラスターでのトランザクションを含む分散トランザクションをサポートします。
分散トランザクションは次のとおりアトミックな性質を持ちます。
トランザクションは、データ変更をすべて適用するか、変更をロールバックします。
トランザクションがコミットされると、トランザクション内で行われたすべてのデータ変更が保存され、トランザクション外でも表示されます。
トランザクションがコミットされるまで、トランザクションで行われたデータ変更はトランザクションの外部には表示されません。
ただし、トランザクションが複数のシャードに書き込む場合、すべての外部読み取り操作が、コミットされたトランザクションの結果がシャード全体で表示されるまで待機する必要はありません。たとえば、トランザクションがコミットされ、書込み 1 がシャード A で表示されているものの、書込み 2 がシャード B にまだ表示されていない場合、読み取り保証(read concern)
"local"での外部読み取りは、書き込み 2 を見ることなく書き込み 1 の結果を読み取ることができます。トランザクションが中止されると、トランザクションで行われたすべてのデータの変更は表示されることなく破棄されます。
重要
ほとんどの場合、分散トランザクションでは 1 つのドキュメントの書き込み (write) よりもパフォーマンス コストが高くなります。分散トランザクションの可用性は、効果的なスキーマ設計の代わりにはなりません。多くのシナリオにおいて、非正規化されたデータモデル(埋め込みドキュメントと配列)が引き続きデータやユースケースに最適です。つまり、多くのシナリオにおいて、データを適切にモデリングすることで、分散トランザクションの必要性を最小限に抑えることができます。
トランザクションの使用に関するその他の考慮事項(ランタイム制限や oplog サイズ制限など)については、「本番環境での考慮事項」も参照してください。
Tip
トランザクションと操作
トランザクションは、複数の操作、コレクション、データベース、ドキュメント、シャードにわたって使用できます。
トランザクションについて:
トランザクション内でコレクションとインデックスを作成できます。詳細については、「トランザクション内でのコレクションとインデックスの作成」を参照してください。
トランザクションで使用されるコレクションは、異なるデータベースにある可能性があります。
注意
クロスシャードの書き込みトランザクションでは新しいコレクションを作成できません。たとえば、あるシャードで既存コレクションに書き込み、別のシャードで暗示的にコレクションを作成する場合、MongoDB では同じトランザクションで両方の操作を実行できません。
Capped コレクションには書き込めません。
Capped コレクションから読み取る場合、読み取り保証(read concern)
"snapshot"は使用できません。(MongoDB 5.0 以降)configデータベース、adminデータベース、またはlocalデータベース内のコレクションの読み取りと書き込みはできません。system.*コレクションに書き込み (write) はできません。explainまたは類似コマンドを使用して、サポートされている操作のクエリプランを返すことはできません。
トランザクションの外部で作成されたカーソルの場合、トランザクション内で
getMoreを呼び出せません。トランザクション内で作成されたカーソルの場合、トランザクション外で
getMoreを呼び出せません。
killCursorsコマンドをトランザクションの最初の操作に指定することはできません。さらに、トランザクション内で
killCursorsコマンドを実行すると、サーバーは指定されたカーソルを直ちに停止します。トランザクションがコミットされるのを待ちません。
トランザクションでサポートされない操作のリストについては、「制限付き操作」を参照してください。
Tip
トランザクションを開始する直前にコレクションを作成または削除する際に、トランザクション内のコレクションにアクセスする場合、書込み保証(write concern)付きで "majority" に作成または削除操作を発行して、トランザクションが必要なロックを取得できるようにします。
トランザクション内でのコレクションとインデックスの作成
トランザクションが クロスシャード書込みトランザクション (write transaction)でない場合、トランザクション内で次の操作を実行できます。
コレクションを作成する。
同じトランザクション内で以前に作成された新しい空のコレクションにインデックスを作成する
トランザクション内でコレクションを作成する際、以下を実行できます。
暗黙的にコレクションを作成できます。たとえば次のいずれかを使用します。
存在しないコレクションに対する挿入操作。
存在しないコレクションを
upsert: trueに設定した update/findAndModify 操作。
createコマンドまたはそのヘルパーであるdb.createCollection()を使用して、明示的にコレクションを作成できます。
トランザクション内でインデックスを作成する場合 [1]、作成するインデックスは次のいずれかに配置される必要があります。
存在しないコレクション。コレクションは、操作中に作成されます。
同じトランザクション内で以前に作成された新しい空のコレクション。
| [1] | 既存インデックスに対して db.collection.createIndex() と db.collection.createIndexes() を実行して、その有無を確認することもできます。これらの操作は、インデックスを作成せずに正常に返されます。 |
制限事項
クロスシャードの書き込みトランザクションでは新しいコレクションを作成できません。たとえば、あるシャードで既存コレクションに書き込み、別のシャードで暗示的にコレクションを作成する場合、MongoDB では同じトランザクションで両方の操作を実行できません。
シャーディングされたコレクションをターゲットにしている間は、トランザクション内で
$graphLookupステージを使用できません。トランザクション内でコレクションまたはインデックスを明示的に作成する場合、トランザクションの読み取り保証(read concern)は
"local"でなければなりません。コレクションとインデックスを明示的に作成するには、次のコマンドとメソッドを使用します。
Tip
カウント操作
トランザクション内でカウント操作を実行するには、$count 集計ステージまたは $group($sum式を使用) 集計ステージを使用します。
MongoDB ドライバーは、$group と $sum 式を併用してカウントを実行するヘルパー メソッドとして、コレクションレベルの API countDocuments(filter, options)を提供します。
mongosh には、$group を $sum 式と併用してカウントを実行する db.collection.countDocuments() ヘルパー メソッドが用意されています。
個別の操作
トランザクション内で個別の操作を実行するには、以下を使用できます。
シャーディングされていないコレクションの場合、
db.collection.distinct()メソッドまたはdistinctコマンド、および 集計パイプラインを$groupステージと併用できます。シャーディングされたコレクションの場合、
db.collection.distinct()メソッド、またはdistinctコマンドは使用できません。シャーディングされたコレクションの個別の値を検索するには、代わりに
$groupステージで集計パイプラインを使用します。以下に例を挙げます。db.coll.distinct("x")の代わりに以下を使用しますdb.coll.aggregate([ { $group: { _id: null, distinctValues: { $addToSet: "$x" } } }, { $project: { _id: 0 } } ]) db.coll.distinct("x", { status: "A" })の代わりに以下を使用します。db.coll.aggregate([ { $match: { status: "A" } }, { $group: { _id: null, distinctValues: { $addToSet: "$x" } } }, { $project: { _id: 0 } } ])
パイプラインはドキュメントにカーソルを返します。
{ "distinctValues" : [ 2, 3, 1 ] } カーソルを反復して、結果ドキュメントにアクセスします。
情報に関する操作
情報提供コマンドには、hello、buildInfo、connectionStatus(およびこれらのヘルパー メソッド)などがあり、トランザクションに含めることができますが、最初の操作になることはできません。
制限付き操作
次の操作はトランザクションでは許可されません。
クロスシャードの書き込みトランザクションで新しいコレクションを作成します。たとえば、あるシャードで既存コレクションに書き込み、別のシャードで暗示的にコレクションを作成する場合、MongoDB では同じトランザクションで両方の操作を実行できません。
コレクションの明示的な作成(
db.createCollection()メソッドやインデックスの明示的な作成(db.collection.createIndexes()およびdb.collection.createIndex()メソッドなど)で、"local"以外の読み取り保証(read concern)レベルを使用する場合listCollectionsコマンドとlistIndexesコマンド、およびそのヘルパー メソッド。その他の CRUD 操作や情報操作以外の操作、例えば
createUser、getParameter、countなどおよびその補助ツール。並列操作。複数の名前空間を同時に更新するには、
bulkWriteコマンドの使用を検討してください。
トランザクションとセッション
トランザクションはセッションに関連付けられます。
1 セッションで一度に開くことができるトランザクションは 1 つまでです。
ドライバーを使用する場合、トランザクション内の各操作はセッションに関連付けられる必要があります。詳細については、ドライバー固有のドキュメントを参照してください。
セッションが終了し、そのセッションにオープン トランザクションがある場合、そのトランザクションは中止されます。
読み取り保証 (read concern)、書込み保証 (write concern)、読み込み設定 (read preference)
トランザクションと読み込み設定(read preference)
トランザクション内の操作では、トランザクションレベルの読み込み設定(read preference)が使用されます。
ドライバーを使用すると、トランザクション開始時にトランザクションレベルの読み込み設定(read preference)を設定できます。
読み込み設定(read preference)がトランザクションレベルで設定されていない場合、セッションレベルの読み込み設定がトランザクションで使用されます。
読み込み設定(read preference)がトランザクションとセッションのいずれのレベルでも設定されていない場合、クライアントレベルの読み込み設定がトランザクションで使用されます。デフォルトでは、クライアントレベルの読み込み設定が
primaryとなります。
読み取り操作を含むトランザクションでは、読み込み設定 (read preference) primaryを使用する必要があります。特定のトランザクション内のすべての操作は、同じノードにルーティングする必要があります。
トランザクションと読み取り保証
トランザクション内の操作では、トランザクションレベルの読み取り保証(read concern)が使用されます。つまり、コレクションレベルとデータベースレベルで設定された読み取り保証は、トランザクション内では無視されます。
トランザクションの開始時に、トランザクションレベルの読み取り保証(read concern)を設定できます。
トランザクションレベルの読み取り保証(read concern)の設定が解除されている場合、トランザクションレベルの読み取り保証はデフォルトでセッションレベルの読み取り保証になります。
トランザクションレベルとセッションレベルの読み取り保証(read concern)の設定が解除されている場合、トランザクションレベルの読み取り保証はデフォルトでクライアントレベルの読み取り保証に設定されます。デフォルトでは、クライアントレベルの読み取り保証は プライマリでの読み取りで
"local"となります。以下も参照してください。
トランザクションは次の読み取り保証(read concern)レベルをサポートします。
"local"
読み取り保証(read concern)
"local"は、ノードから入手可能な最新データを返しますが、ロールバックも可能です。レプリカセットでは、トランザクションが読み取り保証
localを使用している場合でも、トランザクションが開かれた時点でのスナップショットから操作が読み取られる場合、より強力な読み取り分離が見られる可能性があります。シャーディングされたクラスター上のトランザクションの場合、
"local"読み取り保証(read concern)では、シャード全体でデータが同じスナップショット ビューから取得されることを保証できません。スナップショットの分離が必要な場合は、"snapshot"読み取り保証(read concern)を使用してください。トランザクション内でコレクションとインデックスを作成できます。コレクションまたはインデックスを明示的に作成する場合、トランザクションで読み取り保証
"local"を使用する必要があります。コレクションを暗黙的に作成する場合は、トランザクションに任意の読み取り保証を使用できます。
"majority"
トランザクションが「majority 」の書込み保証(write concern)でコミットされた場合、読み取り保証(read concern)
"majority"はレプリカセット ノードの過半数によって確認済みであり、かつロールバックできないデータを返します。それ以外の場合、読み取り保証"majority"では読み取り操作によって過半数のコミット済みデータが読み取られる保証はありません。シャーディングされたクラスター上のトランザクションの場合、読み取り保証(read concern)
"majority"では、シャード全体でデータが同じスナップショット ビューから取得されることを保証できません。スナップショットの分離が必要な場合は、読み取り保証"snapshot"を使用します。
"snapshot"
トランザクションが「majority 」の書込み保証(write concern)でコミットされる場合、読み取り保証(read concern)
"snapshot"はコミットされた過半数のデータのスナップショットからのデータを返します。トランザクションが「過半数」の書込み保証(write concern)をコミットに使用しない場合、
"snapshot"読み取り保証(read concern)は、読み取り操作によってコミットされた過半数のデータのスナップショットが使用されたことを保証しません。シャーディングされたクラスター上のトランザクションの場合、データの
"snapshot"ビューはシャード間で同期されます。
トランザクションと書込み保証
トランザクションは、トランザクションレベルの書込み保証 (write concern)を使用して書込み操作をコミットします。トランザクション内の書込み操作は、明示的な書込み保証 (write concern)保証を指定せずに、デフォルトの書込み保証 (write concern)を使用して実行される必要があります。コミット時に、書込み操作はトランザクションレベルの書込み保証 (write concern)を使用してコミットされます。
Tip
トランザクション内の個々の書込み操作に書込み保証(write concern)を明示的に設定しないでください。トランザクション内の個々の書込み操作に書込み保証を設定すると、エラーが返されます。
トランザクションの開始時に、トランザクションレベルの書込み保証(write concern)を設定できます。
トランザクションレベルの書込み保証(write concern)の設定が解除されている場合、トランザクションレベルの書込み保証はデフォルトでセッションレベルの書込み保証でコミットされます。
トランザクションレベルとセッションレベルのいずれでも書込み保証(write concern)の設定が解除されている場合、トランザクションレベルの書込み保証はデフォルトでクライアントレベルの書込み保証になります。
w: "majority"(MongoDB 5.0 以降の場合)。アービタを含む配置では差異があります。詳細については、「暗黙のデフォルト書込み保証(write concern)」を参照してください。
トランザクションは、以下を含むすべての書込み保証(write concern)の w 値をサポートします。
w: 1
書込み保証(write concern)
w: 1は、コミットがプライマリに適用された後に確認応答を返します。重要
w: 1でコミットする場合、トランザクションはフェイルオーバーが発生した場合にロールバック可能です。w: 1書込み保証(write concern)でコミットする場合、トランザクションレベルの"majority"読み取り保証(read concern)では、トランザクション内の読み取り操作が過半数でコミットされたデータを読み取るという保証は ありません。w: 1書込み保証(write concern)でコミットする場合、トランザクションレベルの"snapshot"読み取り保証(read concern)では、トランザクション内の読み取り操作で過半数でコミットされたデータのスナップショットが使用されるという保証は ありません。
w: "majority"
w: "majority"の書込み保証(write concern)は、コミットが投票ノードの過半数に適用された後に確認応答を返します。w: "majority"書込み保証(write concern) でコミットする場合、トランザクションレベルの"majority"読み取り保証(read concern)により、操作によって過半数でコミットされたデータが読み取られたことが保証されます。シャーディングされたクラスター上のトランザクションでは、コミットされた過半数のデータのこのビューはシャード間で同期されません。w: "majority"書込み保証(write concern)でコミットする場合、トランザクションレベルの"snapshot"読み取り保証(read concern)により、操作によって過半数でコミットされたデータの同期されたスナップショットから読み取られたことが保証されます。
注意
トランザクションに指定された書込み保証(write concern)にかかわらず、シャーディングされたトランザクションに対するコミット操作の一部には、{w:
"majority", j: true} 書込み保証を使用する部分が含まれます。
サーバー パラメーター coordinateCommitReturnImmediatelyAfterPersistingDecision は、トランザクションをコミットする決定がクライアントに返されるタイミングを制御します。
このパラメーターは MongDB 5.0 で導入されたもので、デフォルト値はtrue です。MongoDB 6.1 ではデフォルト値が false に変更されています。
coordinateCommitReturnImmediatelyAfterPersistingDecision が false の場合、 シャードトランザクションの調整役は、トランザクションのコミットの決定をクライアントに返す前に、すべてのノードがトランザクションのコミットを確認するまで待機します。
"majority" 書き込みに対して書込み保証 (write concern)を指定し、かつ操作が応答を返す前に 計算された過半数 の レプリカセット ノードに複製されない場合、データは最終的に複製またはロールバックされます。wtimeout を参照してください。
トランザクションに指定された書込み保証(write concern)にかかわらず、ドライバーは commitTransaction の再試行時に書込み保証として w: "majority" を適用します。
トランザクションに関する考慮事項
以下のセクションでは、デプロイメントタイプ、ストレージエンジン、およびMongoDB のバージョンによって異なるトランザクションの要件と考慮事項について説明します。
本番環境での考慮事項
本番環境でのトランザクションについては、「本番環境での考慮事項」を参照してください。シャーディングされたクラスターについては、「本番環境での考慮事項(シャーディングされたクラスター)」も参照してください。
アービタ
レプリカセットにアービタがある場合、トランザクションを使用してシャードキーを変更することはできません。 アービタは、 マルチシャード トランザクションに必要なデータ操作に参加することはできません。
書込み操作が複数のシャードにまたがるトランザクションで、アービタを含むシャードを対象に読み取りまたは書込み操作が実行される場合、そのトランザクションはエラーとなり中止します。
シャード構成の制限
シャーディングされたクラスターのうち writeConcernMajorityJournalDefault が false に設定されているもの(インメモリ ストレージエンジンを使用する投票ノードのあるシャードなど)ではトランザクションを実行できません。
注意
トランザクションに指定された書込み保証(write concern)にかかわらず、シャーディングされたトランザクションに対するコミット操作の一部には、{w:
"majority", j: true} 書込み保証を使用する部分が含まれます。
診断
トランザクションのステータスとメトリクスを取得するには、次のメソッドを使用します。
ソース | 戻り値 |
|---|---|
db.serverStatus() methodserverStatus command | トランザクション メトリクスを返します。 MongoDB Atlas無料クラスターまたは Flex クラスターでは、一部の |
| 次の値を返します。
|
db.currentOp() methodcurrentOp command | 次の値を返します。
|
低速( |
機能の互換性バージョン(fCV)
トランザクションを使用するには、配置のすべてのノードの FeatureCompatibilityVersion が次のバージョン以上である必要があります。
配置 | 最小 featureCompatibilityVersion |
|---|---|
レプリカセット |
|
シャーディングされたクラスター |
|
ノードの機能の互換性バージョンを確認するには、該当ノードに接続して次のコマンドを実行します。
db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )
詳細については、setFeatureCompatibilityVersion に関する参考ページを参照してください。
ストレージ エンジン
トランザクションは、次のレプリカセットとシャーディングされたクラスターでサポートされます。
プライマリが WiredTiger ストレージエンジンを使用しており、かつ
セカンダリ ノードが、WiredTiger ストレージエンジンまたはインメモリ ストレージエンジンのいずれかを使用している。
注意
シャーディングされたクラスターのうち writeConcernMajorityJournalDefault が false に設定されているもの(インメモリ ストレージエンジンを使用する投票ノードのあるシャードなど)ではトランザクションを実行できません。
クリティカル セクションの待機時間の制限
MongoDB 5.2 以降(および 5.0.4で)、以下の項目が適用されます。
クエリがシャードにアクセスしたときに、チャンク移行または DDL 操作によってコレクションのクリティカル セクションが保持されている可能性があります。
トランザクション内のクリティカル セクションをシャードが待機する時間を制限するには、
metadataRefreshInTransactionMaxWaitMSパラメーターを使用します。注意
MongoDB 8.1 以降では、古い
metadataRefreshInTransactionMaxWaitBehindCritSecMSパラメータの名前がmetadataRefreshInTransactionMaxWaitMSに変更されます。パラメータ名としてmetadataRefreshInTransactionMaxWaitBehindCritSecMSを引き続き使用できますが、これは非推奨であり、今後のMongoDBリリースで削除される予定です。