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

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

 

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

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

前提条件

SELECT ANY TABLE、INSERT ANY TABLE、DELETE ANY SYSTEM のシステム権限が必要です。

このチュートリアルでは、Sales Manager および Accountant としてサンプルデータベースに接続していると仮定します。チュートリアル:独立性レベルのチュートリアルのシナリオ設定を参照してください。

注意

このチュートリアルを正常に機能させるには、Interactive SQL の [データベースロックの自動解放] オプションをオフにする必要があります。このオプションの設定を確認するには、[ツール] » [オプション] をクリックし、左ウィンドウ枠の [SQL Anywhere] をクリックします。

内容と備考

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

 ♦ タスク
  1. 次の文を実行して、Sales Manager と Accountant のウィンドウにそれぞれ独立性レベル 2 を設定します。

    SET TEMPORARY OPTION isolation_level = 2;
  2. 毎月、販売担当者には、その月の各人の売り上げ高に対し、一定の割合のコミッションが支払われます。Accountant は、2001 年 4 月分のコミッションの小切手を準備しています。彼の最初のタスクは、その月の各担当者の売り上げ合計額を計算することです。価格、注文情報、従業員データがそれぞれ別のテーブルに保存されます。外部キー関係を使用してこれらのテーブルをジョインすることにより、必要な情報を結合します。

    Accountant として、次の文を実行します。



    SELECT EmployeeID, GivenName, Surname,
       SUM( SalesOrderItems.Quantity * UnitPrice )
          AS "April sales"
    FROM GROUPO.Employees
       KEY JOIN GROUPO.SalesOrders
       KEY JOIN GROUPO.SalesOrderItems
       KEY JOIN GROUPO.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
    ... ... ... ...
  3. Sales Manager は、Philip Chin の多額の売り上げがデータベースに入力されていないことに気づきました。Philip はコミッションの迅速な支払いを希望しているため、Sales Manager は 4 月 25 日の彼の漏れていた注文を入力します。

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

    INSERT into GROUPO.SalesOrders
    VALUES ( 2653, 174, '2001-04-22', 'r1',
          'Central', 129 );
    INSERT into GROUPO.SalesOrderItems
    VALUES ( 2653, 1, 601, 100, '2001-04-25' );
    COMMIT;
  4. 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 月の売り上げ合計に含まれていなかったとしても、支払い済みのマークが付いています。

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

    Sales Manager として次の文を実行し、新しい注文を削除します。

    DELETE
    FROM GROUPO.SalesOrderItems
    WHERE ID = 2653;
    DELETE
    FROM GROUPO.SalesOrders
    WHERE ID = 2653;
    COMMIT;
  6. Accountant として、次の文を実行します。

    ROLLBACK;
    SET TEMPORARY OPTION isolation_level = 3;
  7. 次のクエリを実行します。



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

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

  8. Sales Manager として次の文を実行して、Philip Chin の漏れていた注文の入力を試みます。

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

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

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

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

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

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

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

  10. SQL Anywhere サンプルデータベースを防ぐために、SalesOrders テーブルに対する変更をロールバックする必要があります。[Sales Manager] ウィンドウと [Accountant] ウィンドウで、次の文を実行します。

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

結果

幻ロックの動作方法を理解するチュートリアルを完了しました。

 参照