Click here to view and discuss this page in DocCommentXchange. In the future, you will be sent there automatically.

SQL Anywhere 12.0.1 » SQL Anywhere サーバー SQL の使用法 » トランザクションと独立性レベル » 独立性レベルのチュートリアル

 

チュートリアル:幻ロックの知識

このチュートリアルでは、Accountant と Sales Manager はどちらも SalesOrder テーブルと SalesOrderItems テーブルに関わるタスクを行います。Accountant は、2001 年の 4 月に売り上げを上げた販売担当者に支払ったコミッションの小切手額を確認する必要があります。Sales Manager は、データベースに追加されなかった注文がいくつかあることに気づき、それを追加したいと思っています。

彼らの操作で幻ロックについて説明します。「幻ロック」は幻ローを防ぐためにインデックススキャン位置に設定される共有ロックです。独立性レベル 3 のトランザクションが指定された基準を満たすローを選択すると、データベースサーバーは対挿入ロックを設定し、他のトランザクションが基準を満たすローを挿入することを禁止します。設置するロック数は検索基準やデータベースの設計によって異なります。

注意

このチュートリアルが正常に動作するように、Interactive SQL の [データベースロックの自動解放] オプションをオフにしてください。このオプションの設定を確認するには、[ツール]  » [オプション] をクリックし、左ウィンドウ枠の [SQL Anywhere] をクリックします。

 ♦ 幻ロックの作成
  1. Interactive SQL の 2 つのインスタンスを起動します。繰り返し不可能読み出しのチュートリアルの手順 1 ~ 4 を参照してください。チュートリアル:繰り返し不可能読み出しの知識を参照してください。

  2. 次の文を実行して、Sales Manager のウィンドウと Accountant のウィンドウに独立性レベル 2 を設定します。

    SET TEMPORARY OPTION isolation_level = 2;
  3. 毎月、販売担当者には、その月の各人の売り上げ高に対し、一定の割合のコミッションが支払われます。Accountant は、2001 年 4 月分のコミッションの小切手を準備しています。彼の最初のタスクは、その月の各担当者の売り上げ合計額を計算することです。

    Accountant のウィンドウに次の文を入力します。価格、注文情報、従業員データがそれぞれ別のテーブルに保存されます。外部キー関係を使用してこれらのテーブルをジョインすることにより、必要な情報を結合します。



    SELECT EmployeeID, GivenName, Surname,
       SUM( SalesOrderItems.Quantity * UnitPrice )
          AS "April sales"
    FROM Employees
       KEY JOIN SalesOrders
       KEY JOIN SalesOrderItems
       KEY JOIN Products
    WHERE '2001-04-01' <= OrderDate
       AND OrderDate < '2001-05-01'
    GROUP BY  EmployeeID, GivenName, Surname
    ORDER BY EmployeeID;
    EmployeeID GivenName Surname April sales
    129 Philip Chin 2160.00
    195 Marc Dill 2568.00
    299 Rollin Overbey 5760.00
    467 James Klobucher 3228.00
    ... ... ... ...
  4. Sales Manager は、Philip Chin の多額の売り上げがデータベースに入力されていないことに気づきました。Philip はコミッションの迅速な支払いを希望しているため、Sales Manager は 4 月 25 日の彼の漏れていた注文を入力します。

    Sales Manager のウィンドウに次の文を入力します。1 つの注文に多くの品目を含めることができるため、受注と品目は別のテーブルに入力されます。品目を追加する前に、売り上げ注文にエントリを作成します。参照整合性を維持するために、データベースサーバーは注文がすでに存在する場合にかぎり、トランザクションが品目を注文に追加することを許可します。

    INSERT into SalesOrders
    VALUES ( 2653, 174, '2001-04-22', 'r1',
          'Central', 129 );
    INSERT into SalesOrderItems
    VALUES ( 2653, 1, 601, 100, '2001-04-25' );
    COMMIT;
  5. Accountant は、Sales Manager が新しい注文を追加したことを知りません。新しい注文がもっと前に入力された場合は、Philip Chin の 4 月の売り上げ計算に含まれます。

    Accountant のウィンドウで、4 月の売り上げ合計を再計算します。同じ文を使用しますが、Philip Chin の 4 月の売り上げ額が $4560.00 ドルに変更されていることに注意してください。

    EmployeeID GivenName Surname April sales
    129 Philip Chin 4560.00
    195 Marc Dill 2568.00
    299 Rollin Overbey 5760.00
    467 James Klobucher 3228.00
    ... ... ... ...

    ここで、Accountant は 4 月の注文すべてにマークを付けて、コミッションが支払い済みであることを示します。Sales Manager が入力したばかりの注文が 2 度目の検索で見つかりましたが、たとえ Philip の 4 月の売り上げ合計に含まれていなかったとしても、支払い済みのマークが付いています。

  6. 独立性レベル 3 では、データベースサーバーは対挿入ロックを設定し、検索または選択条件に合うローを他のトランザクションが追加できないようにします。

    Sales Manager のウィンドウで、次の文を実行して新しい注文を削除します。

    DELETE
    FROM SalesOrderItems
    WHERE ID = 2653;
    DELETE
    FROM SalesOrders
    WHERE ID = 2653;
    COMMIT;
  7. Accountant のウィンドウで、次の 2 つの文を実行します。

    ROLLBACK;
    SET TEMPORARY OPTION isolation_level = 3;
  8. Accountant のウィンドウで、前と同じクエリを実行します。



    SELECT EmployeeID, GivenName, Surname,
       SUM( SalesOrderItems.Quantity * UnitPrice )
          AS "April sales"
    FROM Employees
       KEY JOIN SalesOrders
       KEY JOIN SalesOrderItems
       KEY JOIN Products
    WHERE '2001-04-01' <= OrderDate
       AND OrderDate < '2001-05-01'
    GROUP BY  EmployeeID, GivenName, Surname;

    独立性レベル 3 を設定したため、データベースサーバーは自動的に対挿入ロックを設定し、Accountant がトランザクションを終了するまで、Sales Manager が 4 月の注文品目を挿入できないようにします。

  9. Sales Manager のウィンドウに戻ります。次の文を実行して、Philip Chin の漏れていた注文の入力を試みます。

    INSERT INTO SalesOrders
    VALUES ( 2653, 174, '2001-04-22',
             'r1','Central', 129 );

    Sales Manager のウィンドウは応答を停止し、操作は完了しません。ツールバーの [停止] をクリック (または [SQL]  » [停止] をクリック) してこのエントリを一時停止します。

  10. Sales Manager は 4 月の注文を入力できませんが、5 月分には入力できると考えます。

    文の日付を 5 月 5 日に変更し、再実行します。

    INSERT INTO SalesOrders
    VALUES ( 2653, 174, '2001-05-05', 'r1',
          'Central', 129 );

    Sales Manager のウィンドウは再度応答を停止します。ツールバーの [停止] をクリック (または [SQL]  » [停止] をクリック) してこのエントリを一時停止します。データベースサーバーでは挿入を防止するために必要となるロック以外は設定しませんが、これらのロックによって、多数のトランザクションの処理が妨げられる可能性があります。

    データベースサーバーはテーブルインデックスにロックをかけます。たとえば、インデックスに幻ロックを設定し、インデックスの直前に新しいローを追加できないようにします。ただし、適切なインデックスが存在しない場合、テーブルのすべてのローにロックをかける必要があります。

    ある状況では、対挿入ロックによって特定テーブルへの挿入のみをブロックできます。

  11. 変更を取り消して SQL Anywhere サンプルデータベースの変更を防止し、このチュートリアルを終了します。Sales Manager のウィンドウで次の文を実行します。

    ROLLBACK;

    Accountant のウィンドウで次の文を実行します。

    ROLLBACK;
  12. Interactive SQL の両方のインスタンスを終了します。