asp.Netでの同時制御

6069 ワード

複数のユーザが同時にデータを変更しようとする場合、1つのユーザの変更が同時に操作する他のユーザの変更に悪影響を及ぼすことを防止するための制御メカニズムを確立する必要がある.このような状況を処理するシステムを「同時制御」と呼ぶ.

同時制御のタイプ


通常、データベース内の同時管理には、次の3つの一般的な方法があります.
  • 保守同時制御-レコードの取得からデータベースに記録された更新までの間、ローはユーザーに対して使用できません.
  • オープン同時制御-実際にデータが更新された場合にのみ、ローは他のユーザーには使用できません.更新では、ローがデータベースでチェックされ、変更が行われたかどうかを確認します.変更されたレコードを更新しようとすると、同時競合が発生します.
  • の最終更新が有効になります.実際にデータが更新された場合にのみ、ローは他のユーザーには使用できません.ただし、更新は初期記録と比較されない.レコードを書き出すだけで、前回のレコードのリフレッシュ後から他のユーザーが行った変更が書き換えられる可能性があります.

  • 保守的同時実行


    保守的な同時実行は、通常、2つの目的で使用されます.第一に、場合によっては、同じ記録に対する大量の競合が存在する.データ上にロックを配置するコストは、同時競合が発生した場合にロールバックして変更するコストよりも小さい.
    トランザクション中にレコードを変更する必要がない場合は、保守的な同時実行も便利です.在庫アプリケーションは良い例です.潜在的な顧客の在庫をチェックしている会社の代表がいると仮定します.通常、受注が生成されるまでレコードをロックします.これは、通常、品目を「受注済」ステータスとしてマークし、使用可能な在庫から削除します.注文が生成されない場合、ロックは解放され、他の在庫をチェックしているユーザーが正確な使用可能在庫数を得ることができます.
    しかし、切り離した構成では保守的な同時制御はできない.接続が開いている時間は、データの読み取りや更新に十分な時間であるため、ロックを長時間保持することはできません.また、ロックを長時間保持しているアプリケーションは伸縮できません.
    ベース・データ・ソースがトランザクションをサポートしている場合は、トランザクションでデータを更新することで、保守的な同時実行をシミュレートできます.詳細については、
    ADO.NETのトランザクション .

    オープンコンカレント


    オープン・コンカレントでは、データベースへのアクセス時にのみロックが設定され、保持されます.これらのロックは、他のユーザが同じ時間にレコードを更新することを防止します.この正確な時刻を更新する以外は、データは常に使用できます.詳細については、オープンコンカレントを参照してください.
    更新しようとすると、変更されたローの初期バージョンがデータベース内の既存のローと比較されます.両者が異なる場合、更新は失敗し、同時エラーが発生します.作成したビジネスロジックを使用して、この2つのローを調整します.

    最終更新有効


    「最終更新が有効」を使用すると、初期データはチェックされず、データベースに更新が書き込まれます.明らかに、次のような状況が発生する可能性があります.
  • ユーザAは、データベースからレコードを取得する.
  • ユーザBは、データベースから同じレコードを取得して変更し、更新されたレコードをデータベースに書き込む.
  • ユーザAは、「古い」レコードを変更し、データベースに書き込む.

  • 上記の場合、ユーザAは、ユーザBによる変更をいつまでも見ることができない.同時制御の「最終更新有効化」メソッドを使用する計画がある場合は、この状況が受け入れられることを確認します.

    ADO.NETとVisual Studio.NETでの同時制御


    データ構造は、切断するデータに基づいているため、ADO.NETとVisual Studio.NETはオープンコンカレントを使用します.そのため、オープン・コンカレントで問題を解決するためにビジネス・ロジックを追加する必要があります.
    オープン・コンカレントを使用する場合は、バージョン・メソッド(実際のバージョン番号または日付タイムスタンプ)とすべての値メソッドを保存する2つの一般的な方法で変更が発生したかどうかを判断できます.

    バージョン番号メソッド


    バージョン番号メソッドでは、更新するレコードに日付タイムスタンプまたはバージョン番号を含む列が必要です.レコードを読み込むと、日付タイムスタンプまたはバージョン番号がクライアントに保存されます.その後、この値は部分的に更新されます.
    同時処理の1つの方法は、WHERE句の値が記録上の値と一致した場合にのみ更新される.このメソッドのSQLの表示形式は次のとおりです.
    UPDATE Table1 SET Column1 = @newvalue1, Column2 = @newvalue2
    WHERE DateTimeStamp = @origDateTimeStamp

    または、バージョン番号を使用して比較できます.
    UPDATE Table1 SET Column1 = @newvalue1, Column2 = @newvalue2
    WHERE RowVersion = @origRowVersionValue

    日付タイムスタンプまたはバージョン番号が一致する場合、データ・ストレージ内のレコードは変更されず、データセットの新しい値を安全に使用してレコードを更新できることを示します.一致しない場合は、エラーが返されます.Visual Studioでコードを作成できます.NETではこの形式の同時検査を実現する.また、更新の競合に応答するためにコードを作成する必要があります.日付タイムスタンプまたはバージョン番号の正確性を確保するには、行の変更時に日付タイムスタンプまたはバージョン番号を更新するために、テーブルにトリガを設定する必要があります.

    すべての値メソッドを保存


    日付タイムスタンプまたはバージョン番号を使用する代わりに、レコードの読み取り時にすべてのフィールドのコピーを取得します.ADO.NETのDataSetオブジェクトは、各変更レコードの2つのバージョンを維持します.初期バージョン(最初にデータソースから読み込まれたバージョン)と変更バージョン(ユーザーの更新を示します).レコードをデータ・ソースに書こうとすると、データ・ラインの初期値がデータ・ソースのレコードと比較されます.一致する場合は、データベースレコードが読み込まれた後も変更されていないことを示します.この場合、データセットで変更された値はデータベースに正常に書き込まれます.
    各コマンドには、データアダプタの4つのコマンド(DELETE、INSERT、SELECT、UPDATE)のパラメータセットがあります.各コマンドには、初期値と現在の値(または値の変更)に使用するパラメータがあります.
    注意初期レコードが存在しないため、新しいレコード(INSERTコマンド)を追加するには現在の値しか必要ありません.レコードの削除(DELETEコマンド)は、削除するレコードを特定するために初期値を使用するだけです.
    次の例では、典型的なクライアント・テーブルを更新するデータセット・コマンドのコマンド・テキストを示します.このコマンドは、ダイナミックSQLとオープン同時実行用に指定されます.
    UPDATE Customers SET CustomerID = @currCustomerID, CompanyName = @currCompanyName, ContactName = @currContactName,
    ContactTitle = currContactTitle, Address = @currAddress, City = @currCity,
    PostalCode = @currPostalCode, Phone = @currPhone, Fax = @currFax
    WHERE (CustomerID = @origCustomerID) AND (Address = @origAddress OR @origAddress IS NULL AND Address IS NULL) AND (City = @origCity OR @origCity IS NULL AND City IS NULL)
    AND (CompanyName = @origCompanyName OR @origCompanyName IS NULL AND CompanyName IS NULL) AND (ContactName = @origContactName OR @origContactName IS NULL AND ContactName IS NULL) AND (ContactTitle = @origContactTitle OR @origContactTitle IS NULL AND ContactTitle IS NULL)
    AND (Fax = @origFax OR @origFax IS NULL AND Fax IS NULL) AND (Phone = @origPhone OR @origPhone IS NULL AND Phone IS NULL) AND (PostalCode = @origPostalCode OR @origPostalCode IS NULL AND PostalCode IS NULL);
    SELECT CustomerID, CompanyName, ContactName, ContactTitle, Address, City,
    PostalCode, Phone, Fax
    FROM Customers WHERE (CustomerID = @currCustomerID)

    9つのSET文パラメータはデータベースに書き込まれる現在の値を表し、9つのWHERE文パラメータは初期レコードの位置を特定するための初期値を表します.
    最初の9つのSET文のパラメータは、パラメータセットの最初の9つのパラメータに対応します.これらのパラメータは、SourceVersionプロパティをCurrentに設定します.
    次の9つのWHERE文パラメータは、オープン同時使用のために使用される.これらのプレースホルダは、各パラメータがSourceVersionプロパティをOriginalに設定するパラメータセットの次の9つのパラメータに対応します.
    SELECT文は、更新後にデータセットをリフレッシュするために使用されます.「≪詳細SQL生成オプション|Advanced SQL Generation Options|Essbase_Studio≫」ダイアログ・ボックスで「≪データセットのリフレッシュ|Refresh Data Set|Essbase_Studio≫」オプションを設定したときに生成されます.
    上のSQLでは名前付きパラメータを使用していますが、
    OleDbDataAdapterコマンドでは疑問符(?)を使用します.パラメータプレースホルダとして使用します.
    デフォルトでは、「データ・アダプタ構成ウィザード」で「オープン・コンカレント」オプションを選択すると、Visual Studioでこれらのパラメータが作成されます.エラー処理コードは、自分のビジネス要件に従って追加されます.ADO.NETは、同時ルールに違反したローを返すDBConcurrencyExceptionオブジェクトを提供します.詳細については、同時エラーの処理を参照してください.