MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
MongoDB - トランザクションのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
MongoDB - トランザクション
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == トランザクションとは、複数のデータベース操作を1つの作業単位としてまとめる機能である。<br> トランザクション内の全ての操作が成功した場合のみ変更がコミットされ、1つでも失敗した場合は全ての変更がロールバックされる。<br> <br> MongoDBは、ACID特性 (Atomicity, Consistency, Isolation, Durability) を保証するトランザクション機能を提供している。<br> <br> MongoDB 4.0以降でマルチドキュメントトランザクションがサポートされ、MongoDB 4.2以降ではシャードクラスタでの分散トランザクションもサポートされている。<br> トランザクション機能を使用するには、レプリカセットまたはシャードクラスタ環境が必要であり、スタンドアロン構成では使用できない。<br> <br><br> == トランザクションの種類 == MongoDBは2種類のトランザクション機能を提供している。<br> <br> ==== 単一ドキュメントのアトミック性 ==== MongoDBは、単一ドキュメントに対する操作を自動的にアトミックに実行する。<br> これには、埋め込みドキュメントや配列を含むドキュメント全体の更新が含まれる。<br> <br> 単一ドキュメントのアトミック操作は、特別なコードや設定なしで常に有効であり、パフォーマンスが高い。<br> MongoDBの設計では、80〜90[%]のユースケースが単一ドキュメントのアトミック性で対応可能である。<br> <br> ==== マルチドキュメントトランザクション ==== 複数のドキュメントや複数のコレクションにまたがる操作を1つのトランザクションとして実行する機能である。<br> <br> サポートバージョン:<br> * MongoDB 4.0以降 *: レプリカセットでのマルチドキュメントトランザクション * MongoDB 4.2以降 *: シャードクラスタでの分散トランザクション <br> マルチドキュメントトランザクションは、複数の操作をまとめて実行し、全てが成功した場合のみコミットする必要がある場合に使用する。<br> <br><br> == 単一ドキュメントのアトミック性 == MongoDBでは、単一ドキュメントへの書き込み操作は自動的にアトミックである。<br> <br> ==== 埋め込みドキュメントの更新 ==== 埋め込みドキュメントや配列を含むドキュメント全体の更新は、アトミックに実行される。<br> <br> 以下の例では、balanceフィールドとlast_transaction埋め込みドキュメント全体が同時に更新される。<br> <syntaxhighlight lang="javascript"> db.accounts.updateOne( { _id: 'account_123' }, { $set: { 'balance': 1500, 'last_transaction': { 'date': new Date(), 'amount': 500, 'type': 'deposit' } } } ) </syntaxhighlight> <br> ==== 使用を推奨する場面 ==== 単一ドキュメントのアトミック性を活用することで、マルチドキュメントトランザクションの必要性を減らすことができる。<br> <br> 推奨される設計パターン:<br> * 関連データを埋め込みドキュメントとして格納 * 配列を使用して関連する複数の値を1つのドキュメントに格納 * 非正規化によるデータの重複を許容 <br> このアプローチにより、パフォーマンスが向上し、トランザクションの複雑さを回避できる。<br> <br><br> == マルチドキュメントトランザクション == 複数のドキュメントや複数のコレクションにまたがる操作を、1つのトランザクションとして実行する機能である。<br> <br> ==== レプリカセットでのトランザクション ==== MongoDB 4.0以降では、レプリカセット環境でマルチドキュメントトランザクションがサポートされている。<br> <br> 前提条件:<br> * レプリカセット構成であること (スタンドアロンでは使用不可) * MongoDB 4.0以降のバージョン * WiredTigerストレージエンジンを使用 <br> ==== シャードクラスタでの分散トランザクション ==== MongoDB 4.2以降では、シャードクラスタ環境でも分散トランザクションがサポートされている。<br> <br> 前提条件を以下に示す。<br> * 全てのシャードがレプリカセット構成であること * MongoDB 4.2以降のバージョン * configサーバがレプリカセット構成であること <br> シャードクラスタでのトランザクションは、複数のシャードにまたがるデータに対して実行できる。<br> <br><br> == トランザクション処理 == MongoDBでトランザクションを実行する基本的な手順を説明する。<br> <br> ==== セッションの開始 ==== トランザクションを実行するには、まずセッションを開始する必要がある。<br> <br> * mongoshでのセッション開始 *: <syntaxhighlight lang="javascript"> const session = db.getMongo().startSession({ readPreference: { mode: 'primary' } }); </syntaxhighlight> <br> ==== トランザクションの開始 ==== セッションを使用してトランザクションを開始する。<br> <br> トランザクションオプションを指定できる。<br> * <code>readConcern</code> *: 読み取り関心レベル * <code>writeConcern</code> *: 書き込み関心レベル * <code>readPreference</code> *: 読み取り設定 <br> <syntaxhighlight lang="javascript"> session.startTransaction({ readConcern: { level: 'snapshot' }, writeConcern: { w: 'majority' } }); </syntaxhighlight> <br> ==== コミット ==== トランザクション内の全ての操作が成功した場合、<code>commitTransaction</code> メソッドを呼び出して変更を確定する。<br> <br> <syntaxhighlight lang="javascript"> session.commitTransaction(); </syntaxhighlight> <br> ==== 中止 ==== エラーが発生した場合やトランザクションをキャンセルする場合は、<code>abortTransaction</code> メソッドを呼び出す。<br> <br> <syntaxhighlight lang="javascript"> session.abortTransaction(); </syntaxhighlight> <br> ==== mongoshでの完全なコード例 ==== 銀行口座間の送金を例とした完全なトランザクション処理の例を示す。<br> <br> 以下の例では、Patの口座から100を引き出し、Sashaの口座に100を入金している。<br> 両方の操作が成功した場合のみコミットされ、いずれかが失敗した場合はロールバックされる。<br> <br> <syntaxhighlight lang="javascript"> const session = db.getMongo().startSession({ readPreference: { mode: 'primary' } }); session.startTransaction({ readConcern: { level: 'snapshot' }, writeConcern: { w: 'majority' } }); try { const accountsCollection = session.getDatabase('bank').accounts; accountsCollection.updateOne( { 'customer': 'Pat' }, { $inc: { 'balance': -100 } }, { session: session } ); accountsCollection.updateOne( { 'customer': 'Sasha' }, { $inc: { 'balance': 100 } }, { session: session } ); session.commitTransaction(); print("トランザクション成功"); } catch (error) { print("トランザクション失敗: " + error); session.abortTransaction(); } finally { session.endSession(); } </syntaxhighlight> <br><br> == withTransaction API == MongoDBは、トランザクション処理を簡素化するための <code>withTransaction</code> コールバックAPIを提供している。<br> <br> ==== 自動リトライ機能 ==== <code>withTransaction</code> メソッドは、以下に示す機能を自動的に提供する。<br> * トランザクションの開始 * コールバック関数の実行 * 一時的なエラー発生時の自動リトライ (TransientTransactionError) * コミット操作の自動リトライ (UnknownTransactionCommitResult) * エラー時の自動中止 <br> これにより、手動でエラーハンドリングやリトライロジックを実装する必要がなくなる。<br> <br> ==== mongoshでのコード例 ==== <code>withTransaction</code> を使用した送金処理の例を示す。<br> <br> <syntaxhighlight lang="javascript"> const session = db.getMongo().startSession(); function transferFunds(session) { const accountsCollection = session.getDatabase('bank').accounts; accountsCollection.updateOne( { 'customer': 'Pat' }, { $inc: { 'balance': -100 } }, { session: session } ); accountsCollection.updateOne( { 'customer': 'Sasha' }, { $inc: { 'balance': 100 } }, { session: session } ); } try { session.withTransaction(transferFunds, { readConcern: { level: 'snapshot' }, writeConcern: { w: 'majority' } }); print("トランザクション成功"); } catch (error) { print("トランザクション失敗: " + error); } finally { session.endSession(); } </syntaxhighlight> <br> <code>withTransaction</code> メソッドは、コールバック関数内の処理を自動的にトランザクションとして実行し、エラー処理とリトライを管理する。<br> <br><br> == 読み取り関心レベル == 読み取り関心レベル (Read Concern) は、トランザクション内でのデータの読み取り一貫性を制御する設定である。<br> <br> ==== local ==== ローカルノードで利用可能な最新のデータを読み込む。<br> <br> * 最も高速 * 一貫性の保証なし * ロールバックされる可能性のあるデータを読み込む場合がある <br> * 設定例 *: <syntaxhighlight lang="javascript"> session.startTransaction({ readConcern: { level: 'local' } }); </syntaxhighlight> <br> ==== majority ==== レプリカセットの過半数のノードで確認されたデータのみを読み込む。<br> <br> * 耐久性が保証される * ロールバックされることがない * localより遅いが、一貫性が高い <br> * 設定例 *: <syntaxhighlight lang="javascript"> session.startTransaction({ readConcern: { level: 'majority' } }); </syntaxhighlight> <br> ==== snapshot ==== 特定時点の一貫したスナップショットからデータを読み込む。<br> <br> * トランザクション内で推奨されるレベル * 読み取り中の他の書き込み操作の影響を受けない * 完全な分離性を保証 <br> トランザクション内では、<code>snapshot</code> レベルが最も推奨される。<br> <br> * 設定例 *: <syntaxhighlight lang="javascript"> session.startTransaction({ readConcern: { level: 'snapshot' } }); </syntaxhighlight> <br><br> == 書き込み関心レベル == 書き込み関心レベル (Write Concern) は、書き込み操作の確認レベルを制御する設定である。<br> <br> ==== w: 1 ==== プライマリノードのみで書き込みを確認する。<br> <br> * デフォルト設定 * 最も高速 * プライマリノード障害時にデータ損失の可能性がある <br> * 設定例 *: <syntaxhighlight lang="javascript"> session.startTransaction({ writeConcern: { w: 1 } }); </syntaxhighlight> <br> ==== w: "majority" ==== レプリカセットの過半数のノードで書き込みを確認する。<br> <br> * 高い耐久性 * ノード障害時でもデータが保持される * w: 1より遅い <br> * 設定例 *: <syntaxhighlight lang="javascript"> session.startTransaction({ writeConcern: { w: 'majority' } }); </syntaxhighlight> <br> ==== j: true ==== ジャーナルへの永続化を待機する。<br> <br> * 最も安全 * ディスクへの書き込み完了を確認 * パフォーマンスへの影響が大きい <br> * 設定例 *: <syntaxhighlight lang="javascript"> session.startTransaction({ writeConcern: { w: 'majority', j: true } }); </syntaxhighlight> <br> ==== wtimeout ==== 書き込み確認の待機時間をミリ秒単位で指定する。<br> <br> 以下の例では、5秒以内に過半数のノードで確認されない場合、エラーが発生する。<br> <br> * 設定例 *: <syntaxhighlight lang="javascript"> session.startTransaction({ writeConcern: { w: 'majority', wtimeout: 5000 } }); </syntaxhighlight> <br><br> == 読み取り設定 == 読み取り設定 (Read Preference) は、レプリカセット内のどのメンバーから読み取りを行うかを指定する設定である。<br> <br> ==== primary ==== 常にプライマリノードから読み取る。<br> <br> * デフォルト設定 * 最新のデータを保証 * トランザクション内で推奨される設定 <br> * 設定例 *: <syntaxhighlight lang="javascript"> const session = db.getMongo().startSession({ readPreference: { mode: 'primary' } }); </syntaxhighlight> <br> ==== secondary ==== セカンダリノードから読み取る。<br> <br> * プライマリノードの負荷を軽減 * トランザクション内では制限がある <br> <u>※注意</u><br> <u>マルチドキュメントトランザクション内では、読み取り設定は <code>primary</code> である必要がある。</u><br> <u><code>secondary</code> や他の設定を使用すると、エラーが発生する。</u><br> <br><br> == タイムアウトと制限事項 == MongoDBトランザクションには、いくつかのタイムアウト設定と制限事項がある。<br> <br> ==== transactionLifetimeLimitSeconds ==== トランザクションの最大実行時間を秒単位で指定する。<br> この時間を超えると、トランザクションは自動的に中止される。<br> <br> * デフォルト値 *: 60秒 <br> * 設定変更の方法 *: <syntaxhighlight lang="javascript"> db.adminCommand({ setParameter: 1, transactionLifetimeLimitSeconds: 120 }) </syntaxhighlight> <br> ==== maxTransactionLockRequestTimeoutMillis ==== トランザクションがロック取得を待機する最大時間をミリ秒単位で指定する。<br> この時間内にロックを取得できない場合、トランザクションは中止される。<br> <br> * デフォルト値 *: 5ミリ秒 <br> ==== maxTimeMS ==== 個々の操作の最大実行時間をミリ秒単位で指定する。<br> <br> * 設定例 *: <syntaxhighlight lang="javascript"> db.collection.find().maxTimeMS(5000); </syntaxhighlight> <br> ==== シャードクラスタでの制限 ==== シャードクラスタでトランザクションを使用する場合、以下に示す制限がある。<br> <br> * トランザクション内の全ての操作のデータサイズは16[MB]以内 * トランザクションの実行時間はデフォルト60秒以内 * 全てのシャードがレプリカセット構成である必要がある。 * Read Concernは <code>snapshot</code> または <code>majority</code> が推奨される。 <br> ==== コレクション作成の制限 ==== トランザクション内で新しいコレクションを作成することはできない。<br> <br> トランザクション実行前にコレクションを作成しておく必要がある。<br> <br> <syntaxhighlight lang="javascript"> db.createCollection('newCollection'); const session = db.getMongo().startSession(); session.startTransaction(); session.getDatabase('testDB').newCollection.insertOne({ a: 1 }, { session: session }); session.commitTransaction(); </syntaxhighlight> <br><br> == Pythonでのトランザクション == PyMongoを使用したトランザクション処理の例を示す。<br> <br> ==== with_transactionコールバックAPIの使用例 ==== PyMongoは、<code>with_transaction</code> メソッドを提供しており、自動的にエラーハンドリングとリトライを行う。<br> <br> <syntaxhighlight lang="python"> from pymongo import MongoClient from pymongo.errors import OperationFailure client = MongoClient('mongodb://localhost:27017/') db = client['bank_db'] session = client.start_session() def transfer_funds(session): accounts = db.accounts accounts.update_one( {'_id': 'account_a'}, {'$inc': {'balance': -100}}, session=session ) accounts.update_one( {'_id': 'account_b'}, {'$inc': {'balance': 100}}, session=session ) try: session.with_transaction(transfer_funds) print("トランザクション成功") except OperationFailure as e: print(f"トランザクション失敗: {e}") finally: session.end_session() </syntaxhighlight> <br> ==== 手動トランザクション管理の使用例 ==== 手動でトランザクションの開始、コミット、中止を管理する例を示す。<br> <br> 手動管理では、トランザクションオプションをより詳細に制御することができる。<br> <br> <syntaxhighlight lang="python"> from pymongo import MongoClient client = MongoClient('mongodb://localhost:27017/') db = client['bank_db'] session = client.start_session() try: session.start_transaction( read_concern={'level': 'snapshot'}, write_concern={'w': 'majority', 'j': True} ) accounts = db.accounts accounts.update_one( {'_id': 'account_a'}, {'$inc': {'balance': -100}}, session=session ) accounts.update_one( {'_id': 'account_b'}, {'$inc': {'balance': 100}}, session=session ) session.commit_transaction() print("トランザクションコミット成功") except Exception as e: session.abort_transaction() print(f"トランザクション中止: {e}") finally: session.end_session() </syntaxhighlight> <br><br> == Node.jsでのトランザクション == MongoDB Node.jsドライバを使用したトランザクション処理の例を示す。<br> <br> ==== withTransactionコールバックAPI ==== Node.jsドライバも <code>withTransaction</code> メソッドを提供している。<br> <br> <syntaxhighlight lang="javascript"> const { MongoClient } = require('mongodb'); async function main() { const client = new MongoClient('mongodb://localhost:27017/'); try { await client.connect(); const db = client.db('bank_db'); const session = client.startSession(); const transferCallback = async () => { const accounts = db.collection('accounts'); await accounts.updateOne( { _id: 'account_a' }, { $inc: { balance: -100 } }, { session } ); await accounts.updateOne( { _id: 'account_b' }, { $inc: { balance: 100 } }, { session } ); }; await session.withTransaction(transferCallback, { readConcern: { level: 'snapshot' }, writeConcern: { w: 'majority' } }); console.log('トランザクション成功'); await session.endSession(); } finally { await client.close(); } } main().catch(console.error); </syntaxhighlight> <br> ==== 手動トランザクション管理 ==== 手動でトランザクションを管理する例を示す。<br> <br> <syntaxhighlight lang="javascript"> const { MongoClient } = require('mongodb'); async function main() { const client = new MongoClient('mongodb://localhost:27017/'); try { await client.connect(); const db = client.db('bank_db'); const session = client.startSession(); try { session.startTransaction({ readConcern: { level: 'snapshot' }, writeConcern: { w: 'majority' } }); const accounts = db.collection('accounts'); await accounts.updateOne( { _id: 'account_a' }, { $inc: { balance: -100 } }, { session } ); await accounts.updateOne( { _id: 'account_b' }, { $inc: { balance: 100 } }, { session } ); await session.commitTransaction(); console.log('トランザクションコミット成功'); } catch (error) { await session.abortTransaction(); console.error('トランザクション中止:', error); } finally { await session.endSession(); } } finally { await client.close(); } } main().catch(console.error); </syntaxhighlight> <br><br> == 推奨される事柄 == ==== 単一ドキュメント優先の設計 ==== 可能な限り、単一ドキュメントのアトミック性を活用する設計を優先する。<br> <br> 80〜90[%]のユースケースは、単一ドキュメントのアトミック性で対応可能である。<br> <br> * 関連データを埋め込みドキュメントとして格納する。 * 非正規化を活用してデータの重複を許容する。 * 配列を使用して関連する複数の値を1つのドキュメントに格納する。 <br> ==== 再試行ロジック ==== トランザクションは、一時的なネットワークエラーやリソース競合により失敗する可能性がある。<br> <br> <code>withTransaction</code> メソッドを使用すると、これらの再試行が自動的に処理される。<br> <br> 推奨される再試行戦略を以下に示す。<br> * <code>TransientTransactionError</code> *: トランザクション全体を再試行 * <code>UnknownTransactionCommitResult</code> *: コミット操作のみを再試行 <br> ==== トランザクション実行時間の最小化 ==== トランザクションの実行時間はできるだけ短く保つ。<br> <br> 推奨事項を以下に示す。<br> * トランザクション内で重い計算処理を避ける。 * トランザクション外でデータの検証やビジネスロジックを実行する。。 * トランザクション内では、必要最小限の操作のみを実行する。 <br> デフォルトのタイムアウトは60秒であるため、長時間実行されるトランザクションは避ける。<br> <br> ==== 適切な関心レベルの選択 ==== トランザクションの要件に応じて、適切な読み取り関心レベルと書き込み関心レベルを選択する。<br> <br> 推奨設定を以下に示す。<br> * Read Concern *: <u>snapshot</u> (トランザクション内で推奨) * Write Concern *: <u>{ w: 'majority' }</u> (高い耐久性が必要な場合) <br> パフォーマンスと一貫性のトレードオフを考慮して選択する。<br> <br> ==== パフォーマンス考慮事項 ==== トランザクションは、通常の操作よりもオーバーヘッドが大きい。<br> <br> パフォーマンスの最適化方法を以下に示す。<br> * インデックスを適切に設定してクエリを高速化 * トランザクション内の操作数を最小限に抑える。 * バッチ処理が可能な場合は、バルク操作を検討する。 * モニタリングを実施して、トランザクションのボトルネックを特定する。 <br> ==== エラーハンドリング ==== トランザクション実行時のエラーを適切に処理する。<br> <br> * トランザクション開始前に入力データを検証する。 * try-catch-finallyブロックでエラーを捕捉する。 * エラー発生時は必ず <code>abortTransaction</code> を呼び出す。 * セッションは必ず <code>endSession</code> で終了する。 <br> リソースリークを防ぐため、finallyブロックでセッションを確実に終了する。<br> <br><br> {{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,MongoDB,Database,NoSQL,Transaction,ACID,電気回路,電子回路,基板,プリント基板 |description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux |image=/resources/assets/MochiuLogo_Single_Blue.png }} __FORCETOC__ [[カテゴリ:その他データベース]]
MongoDB - トランザクション
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse