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

トランザクション

このガイドでは、PyMongo ドライバーを使用してトランザクションを実行する方法を学習できます。 トランザクション を使用すると、トランザクションがコミットされるまでデータを変更しない一連の操作を実行できます。 トランザクション内のいずれかの操作でエラーが返された場合、ドライバーはトランザクションをキャンセルし、変更が反映される前にすべてのデータ変更を破棄します。

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

PyMongo を使用すると、 MongoClientインスタンスからClientSession型の新しいセッションを作成できます。 毎回新しいクライアントを作成するのではなく、 MongoClientを複数のセッションやトランザクションで再利用することを推奨します。

警告

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

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

注意

クライアントセッションでは、トランザクションを実行しない場合でも因果整合性が有効になります。

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

保証
説明

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

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

単調な読み取り

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

単調書込み

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

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

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

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

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

因果関係が整合しているセッションでは、 MongoDB は次の操作のみの因果整合性を保証します。

  • majority の読み取り保証 (read concern)がある読み取り操作

  • majority書込み保証 (write concern)を持つ書込み操作

Tip

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

このガイドの例では、 Atlas サンプル データセットsample_restaurants.restaurantsコレクションを使用します。 MongoDB Atlas クラスターを無料で作成して、サンプル データセットをロードする方法については、 「 PyMongo を使い始める 」チュートリアルを参照してください。

start_session()メソッドを使用してセッションを開始した後、返されたClientSessionによって提供される次のメソッドを使用してセッション状態を管理できます。

方式
説明

start_transaction()

このセッションで、指定されたオプションで構成された新しいトランザクションを開始します。セッションで既にトランザクションが実行中の場合はエラーを返します。このメソッドの詳細については、サーバー マニュアルの「startTransaction() ページ」を参照してください。

パラメーター: read_concernwrite_concernread_preferencemax_commit_time_ms
戻り値の型: ContextManager

abort_transaction()

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

commit_transaction()

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

with_transaction()

このセッションでトランザクションを開始し、callbackを1回実行してから、トランザクションをコミットします。例外が発生した場合、このメソッドはコミットまたはトランザクション全体を再試行することがあります。この場合、with_transaction()の1回の呼び出しによってコールバックが複数回呼び出される可能性があります。

パラメータ: callback, read_concern, write_concern, read_preference, max_commit_time_ms
戻り値: callback関数の結果

bind()

セッションをコンテキストマネージャーの範囲内のすべてのデータベース操作にバインドします。ClientSession オブジェクトでこのメソッドを呼び出し、その結果をコンテキストマネージャーとして使用します。これにより、個別の操作ごとに session を渡す必要がなくなります。

パラメータ:end_session True(任意、デフォルトは)
戻り値の型:_BoundSessionContext

end_session()

このセッションを終了します。 トランザクションが開始された場合、このメソッドはそれを中止します。 終了するアクティブなセッションがない場合は、エラーを返します。

ClientSessionには、セッション プロパティを取得し、可変セッション プロパティを変更するメソッドもあります。 これらのメソッドの詳細については、 API ドキュメント を参照してください。

重要

bind(end_session=False) を呼び出す場合は、セッションがリークされないように、セッションの使用が終了したときに明示的に end_session() を呼び出す必要があります。次のコードは、正しい使用パターンと誤った使用パターンを示しています。

# Incorrect: leaks the session because no reference exists to call
# end_session() on once finished with it
with client.start_session().bind(end_session=False):
...
# Correct: end_session=True by default, so session ends automatically
with client.start_session().bind():
...
# Correct: session variable allows explicit cleanup
with client.start_session() as s, s.bind(end_session=False):
...
s.end_session()
# Correct: nested context managers
with client.start_session() as s:
with s.bind():
...

次の例は、以下の手順でセッションを作成し、トランザクションを作成し、複数のドキュメント挿入操作をコミットする方法を示しています。

  1. start_session() メソッドを使用してクライアントからセッションを作成します。bind() メソッドを呼び出して、ブロック内のすべての操作にそれをバインドします。

  2. トランザクションを開始するには、 with_transaction() メソッドを使用します。

  3. 複数のドキュメントを挿入します。セッションはバインドされているため、各操作から session 引数を省略できます。with_transaction() メソッドは挿入操作を実行し、トランザクションをコミットします。いずれかの操作でエラーが発生した場合、with_transaction() はトランザクションをキャンセルします。この方法により、ブロックが終了するときにセッションが適切に閉じられることが保証されます。

  4. client.close()メソッドを使用してサーバーへの接続を閉じます。

対応するコードを表示するには、Synchronous タブまたは Asynchronousタブを選択します。

# Establishes a connection to the MongoDB server
client = MongoClient("<connection string>")
# Defines the database and collection
restaurants_db = client["sample_restaurants"]
restaurants_collection = restaurants_db["restaurants"]
# Function performs the transaction
def insert_documents(session):
restaurants_collection_with_session = restaurants_collection.with_options(
write_concern=WriteConcern("majority"),
read_concern=ReadConcern("local")
)
# Inserts documents within the transaction
restaurants_collection_with_session.insert_one(
{"name": "PyMongo Pizza", "cuisine": "Pizza"}, session=session
)
restaurants_collection_with_session.insert_one(
{"name": "PyMongo Burger", "cuisine": "Burger"}, session=session
)
# Starts a client session
async with client.start_session() as session:
try:
# Uses the with_transaction method to start a transaction, execute the callback, and commit (or abort on error).
session.with_transaction(insert_documents)
print("Transaction succeeded")
except (ConnectionFailure, OperationFailure) as e:
print(f"Transaction failed: {e}")
# Closes the client connection
client.close()
# Establishes a connection to the MongoDB server
client = AsyncMongoClient("<connection string>")
# Defines the database and collection
restaurants_db = client["sample_restaurants"]
restaurants_collection = restaurants_db["restaurants"]
# Function performs the transaction
async def insert_documents(session):
restaurants_collection_with_session = restaurants_collection.with_options(
write_concern=WriteConcern("majority"),
read_concern=ReadConcern("local")
)
# Inserts documents within the transaction
await restaurants_collection_with_session.insert_one(
{"name": "PyMongo Pizza", "cuisine": "Pizza"}, session=session
)
await restaurants_collection_with_session.insert_one(
{"name": "PyMongo Burger", "cuisine": "Burger"}, session=session
)
# Starts a client session
with client.start_session() as session:
try:
# Uses the with_transaction method to start a transaction, execute the callback, and commit (or abort on error).
await session.with_transaction(insert_documents)
print("Transaction succeeded")
except (ConnectionFailure, OperationFailure) as e:
print(f"Transaction failed: {e}")
# Closes the client connection
await client.close()

トランザクションをさらに制御する必要がある場合は、 start_transaction()メソッドを使用できます。 このメソッドを前のセクションで説明した メソッドとcommit_transaction() abort_transaction()メソッドと組み合わせて使用すると、トランザクションのライフサイクルを手動で管理できます。

注意

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

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

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

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

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

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