トランザクションとオプティミスティック同時実行制御Transactions and optimistic concurrency control

データベース トランザクションでは、データの同時変更に対応する、安全で予測可能なプログラミング モデルが提供されます。Database transactions provide a safe and predictable programming model to deal with concurrent changes to the data. SQL Server などの従来のリレーショナル データベースは、ストアド プロシージャやトリガーを使用してビジネス ロジックを記述し、それをサーバーに送信することで、データベース エンジン内で直接実行することができます。Traditional relational databases, like SQL Server, allow you to write the business logic using stored-procedures and/or triggers, send it to the server for execution directly within the database engine. 従来のリレーショナル データベースの場合、2 種類のプログラミング言語に対応することが求められます。1 つは、JavaScript、Python、C#、Java などの (非トランザクションの) アプリケーション プログラミング言語であり、もう 1 つはデータベースによってネイティブに実行されるトランザクションのプログラミング言語 (T-SQL など) です。With traditional relational databases, you are required to deal with two different programming languages the (non-transactional) application programming language such as JavaScript, Python, C#, Java, etc. and the transactional programming language (such as T-SQL) that is natively executed by the database.

Azure Cosmos DB 内のデータベース エンジンでは、スナップショット分離を使用して ACID (原子性、一貫性、分離、持続性) への完全準拠のトランザクションがサポートされています。The database engine in Azure Cosmos DB supports full ACID (Atomicity, Consistency, Isolation, Durability) compliant transactions with snapshot isolation. コンテナーの論理パーティションのスコープ内におけるデータベース操作はすべて、そのパーティションのレプリカによってホストされたデータベース エンジン内でトランザクションとして実行されます。All the database operations within the scope of a container's logical partition are transactionally executed within the database engine that is hosted by the replica of the partition. これらの操作には、書き込み操作 (論理パーティション内の 1 つまたは複数の項目の更新) と読み取り操作の両方が含まれます。These operations include both write (updating one or more items within the logical partition) and read operations. 次の表に、さまざまな操作とトランザクションの種類を示します。The following table illustrates different operations and transaction types:

操作Operation 操作の種類Operation Type 1 つまたは複数の項目のトランザクションSingle or Multi Item Transaction
挿入 (事前/事後トリガーなし)Insert (without a pre/post trigger) 書き込みWrite 単一項目のトランザクションSingle item transaction
挿入 (事前/事後トリガーを使用)Insert (with a pre/post trigger) 書き込みと読み取りWrite and Read 複数項目のトランザクションMulti-item transaction
置換 (事前/事後トリガーなし)Replace (without a pre/post trigger) 書き込みWrite 単一項目のトランザクションSingle item transaction
置換 (事前/事後トリガーを使用)Replace (with a pre/post trigger) 書き込みと読み取りWrite and Read 複数項目のトランザクションMulti-item transaction
Upsert (事前/事後トリガーなし)Upsert (without a pre/post trigger) 書き込みWrite 単一項目のトランザクションSingle item transaction
Upsert (事前/事後トリガーを使用)Upsert (with a pre/post trigger) 書き込みと読み取りWrite and Read 複数項目のトランザクションMulti-item transaction
削除 (事前/事後トリガーなし)Delete (without a pre/post trigger) 書き込みWrite 単一項目のトランザクションSingle item transaction
削除 (事前/事後トリガーを使用)Delete (with a pre/post trigger) 書き込みと読み取りWrite and Read 複数項目のトランザクションMulti-item transaction
ストアド プロシージャの実行Execute stored procedure 書き込みと読み取りWrite and Read 複数項目のトランザクションMulti-item transaction
システムによって開始されるマージ プロシージャの実行System initiated execution of a merge procedure 書き込みWrite 複数項目のトランザクションMulti-item transaction
項目の有効期限 (TTL) に基づいて、システムによって開始される項目削除の実行System initiated execution of deleting items based on expiration (TTL) of an item 書き込みWrite 複数項目のトランザクションMulti-item transaction
読み取りRead 読み取りRead 単一項目のトランザクションSingle-item transaction
変更フィードChange Feed 読み取りRead 複数項目のトランザクションMulti-item transaction
ページ分割された読み取りPaginated Read 読み取りRead 複数項目のトランザクションMulti-item transaction
ページ分割されたクエリPaginated Query 読み取りRead 複数項目のトランザクションMulti-item transaction
ページ分割されたクエリの一部として UDF を実行Execute UDF as part of the paginated query 読み取りRead 複数項目のトランザクションMulti-item transaction

複数項目のトランザクションMulti-item transactions

Azure Cosmos DB を使用すると、ストアド プロシージャ、事前/事後トリガー、ユーザー定義関数 (UDF)、およびマージ プロシージャを JavaScript で記述できます。Azure Cosmos DB allows you to write stored procedures, pre/post triggers, user-defined-functions (UDFs) and merge procedures in JavaScript. Azure Cosmos DB のデータベース エンジン内では、JavaScript の実行がネイティブでサポートされています。Azure Cosmos DB natively supports JavaScript execution inside its database engine. ストアド プロシージャ、事前/事後トリガー、ユーザー定義関数 (UDF)、およびマージ プロシージャをコンテナーに登録すると、それらを後で Azure Cosmos データベース エンジン内でトランザクションとして実行することができます。You can register stored procedures, pre/post triggers, user-defined-functions (UDFs) and merge procedures on a container and later execute them transactionally within the Azure Cosmos database engine. JavaScript でアプリケーション ロジックを記述する場合、制御フロー、変数のスコーピング、割り当て、およびデータベース トランザクション内での例外処理プリミティブの直接統合を JavaScript プログラミング言語で自然に表現することができます。Writing application logic in JavaScript allows natural expression of control flow, variable scoping, assignment, and integration of exception handling primitives within the database transactions directly in the JavaScript language.

JavaScript ベースのストアド プロシージャ、トリガー、UDF、およびマージ プロシージャは、論理パーティション内のすべての項目でのスナップショット分離によって、アンビエント ACID トランザクション内にラップされます。The JavaScript-based stored procedures, triggers, UDFs, and merge procedures are wrapped within an ambient ACID transaction with snapshot isolation across all items within the logical partition. その実行中に JavaScript プログラムで例外がスローされた場合、トランザクション全体が中止され、ロールバックされます。During the course of its execution, if the JavaScript program throws an exception, the entire transaction is aborted and rolled-back. 結果のプログラミング モデルは簡潔でありながら強力なものになります。The resulting programming model is simple yet powerful. JavaScript 開発者は、使い慣れた言語コンストラクトとライブラリ プリミティブを引き続き利用しながら、耐性のあるプログラミング モデルを手に入れることができます。JavaScript developers get a durable programming model while still using their familiar language constructs and library primitives.

データベース エンジン内部で JavaScript を直接実行する機能により、コンテナーの項目に対するデータベース操作が高いパフォーマンスでトランザクション実行されます。The ability to execute JavaScript directly within the database engine provides performance and transactional execution of database operations against the items of a container. さらに、Azure Cosmos データベース エンジンによって JSON および JavaScript がネイティブでサポートされていることから、アプリケーションとデータベースの型システム間にインピーダンス ミスマッチは存在しません。Furthermore, since Azure Cosmos database engine natively supports JSON and JavaScript, there is no impedance mismatch between the type systems of an application and the database.

オプティミスティック コンカレンシーOptimistic concurrency control

オプティミスティック同時実行制御を使用すると、更新によるデータ喪失および削除によるデータ喪失を防ぐことができます。Optimistic concurrency control allows you to prevent lost updates and deletes. 競合する同時実行操作は、項目を保持する論理パーティションによってホストされているデータベース エンジンの通常の排他的ロックの対象となります。Concurrent, conflicting operations are subjected to the regular pessimistic locking of the database engine hosted by the logical partition that owns the item. 論理パーティション内で最新バージョンの項目の更新を試みる 2 つの同時実行操作がある場合、一方の操作は成功し、もう一方の操作は失敗します。When two concurrent operations attempt to update the latest version of an item within a logical partition, one of them will win and the other will fail. しかし、同じ項目を同時に更新しようとしている 2 つの操作またはそのいずれかによって項目のより古い値が以前に読み取られている場合、競合する操作のいずれか一方または両方によって以前に読み取られたその値が本当に項目の最新値であったかどうかは、データベースでは確認されません。However, if one or two operations attempting to concurrently update the same item had previously read an older value of the item, the database doesn’t know if the previously read value by either or both the conflicting operations was indeed the latest value of the item. 幸い、この状況は、2 つの操作がデータベース エンジン内のトランザクション境界に入るのを許可する前にオプティミスティック同時実行制御 (OCC) によって検出できます。Fortunately, this situation can be detected with the Optimistic Concurrency Control (OCC) before letting the two operations enter the transaction boundary inside the database engine. 他のユーザーが加えた変更が自分のデータによって誤って上書きされないように、OCC によって保護されます。OCC protects your data from accidentally overwriting changes that were made by others. また、ご自分が加えた変更により他のユーザーのデータが誤って上書きされることも防ぎます。It also prevents others from accidentally overwriting your own changes.

項目の同時更新は、Azure Cosmos DB の通信プロトコル レイヤーによって OCC の管理下に置かれます。The concurrent updates of an item are subjected to the OCC by Azure Cosmos DB’s communication protocol layer. Azure Cosmos データベースでは、ご自分で更新 (または削除) している項目のクライアント側のバージョンと Azure Cosmos コンテナー内のその項目のバージョンが確実に同じになります。Azure Cosmos database ensures that the client-side version of the item that you are updating (or deleting) is the same as the version of the item in the Azure Cosmos container. これにより、ご自分の書き込みが他のユーザーの書き込みによって誤って上書きされたり、その逆のケースが生じたりしないように、確実に保護されます。This guarantees that your writes are protected from being overwritten accidentally by the writes of others and vice versa. マルチ ユーザー環境では、ご自分が間違ったバージョンの項目を誤って削除または更新しないように、オプティミスティック同時実行制御によって保護されます。In a multi-user environment, the optimistic concurrency control protects you from accidentally deleting or updating wrong version of an item. したがって、項目が "更新によるデータ喪失" または "削除によるデータ喪失" という悩ましい問題から保護されます。As such, items are protected against the infamous “lost update” or “lost delete” problems.

Azure Cosmos コンテナーに格納されている項目はすべて、システム定義の _etag プロパティを備えています。Every item stored in an Azure Cosmos container has a system defined _etag property. _etag の値は、項目が更新されるたびに、サーバーによって自動的に作成および更新されます。The value of the _etag is automatically generated and updated by the server every time the item is updated. _etag をクライアントによって指定される if-match 要求ヘッダーと共に使用して、サーバーで項目を条件付きで更新できるどうかを判別できます。_etag can be used with the client supplied if-match request header to allow the server to decide whether an item can be conditionally updated. if-match ヘッダーの値がサーバーでの _etag の値と一致すると、項目が更新されます。The value of the if-match header matches the value of the _etag at the server, the item is then updated. if-match 要求ヘッダーの値が最新ではなくなると、操作はサーバーによって拒否され、"HTTP 412 前提条件エラー" という応答メッセージが返されます。If the value of the if-match request header is no longer current, the server rejects the operation with an "HTTP 412 Precondition failure" response message. その後、クライアントでは項目の再フェッチを行って、サーバー上の項目の現在のバージョンを取得したり、サーバーにある項目のバージョンを、その項目に対する独自の _etag 値でオーバーライドしたりできます。The client then can re-fetch the item to acquire the current version of the item on the server or override the version of item in the server with its own _etag value for the item. また、_etagif-none-match ヘッダーと共に使用して、リソースの再フェッチが必要かどうかを判断できます。In addition, _etag can be used with the if-none-match header to determine whether a refetch of a resource is needed.

項目の _etag 値は、項目が更新されるたびに変更されます。The item’s _etag value changes every time the item is updated. 項目の置換操作の場合、if-match が要求オプションの一部として明示されている必要があります。For replace item operations, if-match must be explicitly expressed as a part of the request options. 例については、GitHub 内のサンプル コードを参照してください。For an example, see the sample code in GitHub. ストアド プロシージャによって影響を受けたすべての書き込み項目について、_etag 値が暗黙的にチェックされます。_etag values are implicitly checked for all written items touched by the stored procedure. 競合が検出されると、ストアド プロシージャによってトランザクションがロールバックされ、例外がスローされます。If any conflict is detected, the stored procedure will roll back the transaction and throw an exception. この方法では、ストアド プロシージャ内のすべての書き込みまたは書き込みなしがアトミックに適用されます。With this method, either all or no writes within the stored procedure are applied atomically. これは、更新を再び適用し、元のクライアント要求を再試行することをアプリケーションに求めるシグナルです。This is a signal to the application to reapply updates and retry the original client request.

次の手順Next steps

次の記事で、データベース トランザクションとオプティミスティック同時実行制御の詳細を説明します。Learn more about database transactions and optimistic concurrency control in the following articles: