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

SQL Anywhere 11.0.1 (日本語) » SQL Anywhere サーバ - SQL の使用法 » データベースの作成 » トランザクションと独立性レベルの使用 » 独立性レベルのチュートリアル

 

チュートリアル:幻ロー

このチュートリアルでは、表示される幻ローを確認します。

注意

このチュートリアルが正常に動作するためには、Interactive SQL ([ツール] - [オプション] - [SQL Anywhere]) の[データベース・ロックの自動解放] オプションをオフにする必要があります。

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

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

    SET TEMPORARY OPTION isolation_level = 2;
  3. 次のコマンドを実行して、Accountant のウィンドウに独立性レベル 2 を設定します。

    SET TEMPORARY OPTION isolation_level = 2;
  4. Accountant のウィンドウに次のコマンドを入力し、すべての部署をリストします。

    SELECT * FROM Departments
    ORDER BY DepartmentID;
    DepartmentID DepartmentName DepartmentHeadID
    100 R & D 501
    200 Sales 902
    300 Finance 1293
    400 Marketing 1576
    500 Shipping 703
  5. Sales Manager は外国市場に焦点を当てた新しい部署を設定することを決めます。EmployeeID 129 の Philip Chin を新しい部署の責任者にします。

    INSERT INTO Departments
       (DepartmentID, DepartmentName, DepartmentHeadID)
       VALUES(600, 'Foreign Sales', 129);
    COMMIT;

    最後のコマンドは新しい部署に新しいエントリを作成します。このエントリは、Sales Manager のウィンドウのテーブルの一番下に新しいローとして表示されます。

    Sales Manager のウィンドウに次のコマンドを入力し、すべての部署をリストします。

    SELECT *
    FROM Departments
    ORDER BY DepartmentID;
    DepartmentID DepartmentName DepartmentHeadID
    100 R & D 501
    200 Sales 902
    300 Finance 1293
    400 Marketing 1576
    500 Shipping 703
    600 Foreign Sales 129
  6. しかし Accountant は、新しい部署が作成されたことに気づきません。独立性レベル 2 で、データベース・サーバはローを変更しないようにロックをかけますが、他のトランザクションが新しいローを挿入するのを防止するロックはかけていません。

    Accountant は SELECT コマンドを再実行した場合にだけ、新しいローを発見できます。Accountant のウィンドウで SELECT 文を再実行してください。テーブルに新しいローが追加されているのがわかります。

    SELECT *
    FROM Departments
    ORDER BY DepartmentID;
    DepartmentID DepartmentName DepartmentHeadID
    100 R & D 501
    200 Sales 902
    300 Finance 1293
    400 Marketing 1576
    500 Shipping 703
    600 Foreign Sales 129

    新しく追加されたローは、「幻ロー」と呼ばれます。これは、Accountant の観点から見ると、このローがどこからともなく出現した幻のように映るためです。Accountant は独立性レベル 2 で接続されます。このレベルでは、サーバは使用中のローにだけロックをかけます。他のローにはロックがかけられないため、Sales Manager が新しいローを挿入するのを妨げるものはありません。

  7. Accountant は今後そうしたことが起こらないように、現在のトランザクションの独立性レベルを 3 に上げることにします。次のコマンドを Accountant として入力します。

    SET TEMPORARY OPTION isolation_level = 3;
    SELECT *
    FROM Departments
    ORDER BY DepartmentID;
  8. Sales Manager は、大企業を対象にした営業活動を行う新たな部署を追加したいと思っています。Sales Manager のウィンドウで次のコマンドを実行します。

    INSERT INTO Departments
     (DepartmentID, DepartmentName, DepartmentHeadID)
       VALUES(700, 'Major Account Sales', 902);

    Accountant のロックがコマンドをブロックするため、Sales Manager のウィンドウは実行中に一時停止します。ツールバーの [SQL 文の中断] ボタン (または [SQL] - [中断]) をクリックしてこのエントリを一時停止します。

  9. SQL Anywhere サンプル・データベースが変更されないようにするため、Major Account Sales 部署のローを挿入する未完了トランザクションをロールバックし、2 つ目のトランザクションを使用して Foreign Sales 部署を削除してください。

    1. Sales Manager のウィンドウで次のコマンドを実行し、最後の未完了トランザクションをロールバックします。

      ROLLBACK;
    2. Sales Manager のウィンドウで次の 2 つの文を実行し、先に挿入したローを削除し、この操作をコミットします。

      DELETE FROM Departments
      WHERE DepartmentID = 600;
      COMMIT;
説明

Accountant が独立性レベルを 3 に上げ、Departments テーブルのすべてのローを再度選択した場合、データベース・サーバはテーブルの各ローに対挿入ロックを設定し、新しいローの挿入を防止するためにテーブルの最後にもう 1 つ幻ロックを設定します。Sales Manager がテーブルの最後に新しいローを挿入しようとすると、そのコマンドはこの最後のロックによってブロックされます。

Sales Manager は独立性レベル 2 で接続されているにもかかわらず、Sales Manager のコマンドはブロックされました。データベース・サーバは、独立性レベルと各トランザクション文の要求に応じて、読み込みロックと同様に幻ロックを設定します。一度対挿入ロックが設定されると、このロックは同時に実行される他のすべてのトランザクションに適用されます。

ロックの詳細については、ロックの仕組みを参照してください。

スナップショット・アイソレーションを使用した幻ローの回避

snapshot 独立性レベルを使用すると、独立性レベル 3 と同じレベルで一貫性を維持することができ、ブロックが発生しません。Sales Manager のコマンドはブロックされず、Accountant は幻ローを認識しません。

まだ実行していない場合は、チュートリアル:幻ローの手順 1 から 4 を実行してください。Interactive SQL が 2 つ起動されます。

  1. 次のコマンドを実行し、Accountant のスナップショット・アイソレーションを有効にします。

    SET OPTION PUBLIC. allow_snapshot_isolation = 'On';
    SET TEMPORARY OPTION isolation_level = snapshot;
  2. Accountant のウィンドウに次のコマンドを入力し、すべての部署をリストします。

    SELECT * FROM Departments
    ORDER BY DepartmentID;
    DepartmentID DepartmentName DepartmentHeadID
    100 R & D 501
    200 Sales 902
    300 Finance 1293
    400 Marketing 1576
    500 Shipping 703
  3. Sales Manager は外国市場に焦点を当てた新しい部署を設定することを決めます。EmployeeID 129 の Philip Chin を新しい部署の責任者にします。

    INSERT INTO Departments
       (DepartmentID, DepartmentName, DepartmentHeadID)
       VALUES(600, 'Foreign Sales', 129);
    COMMIT;

    最後のコマンドは新しい部署に新しいエントリを作成します。このエントリは、Sales Manager のウィンドウのテーブルの一番下に新しいローとして表示されます。

    SELECT * FROM Departments
    ORDER BY DepartmentID;
    DepartmentID DepartmentName DepartmentHeadID
    100 R & D 501
    200 Sales 902
    300 Finance 1293
    400 Marketing 1576
    500 Shipping 703
    600 Foreign Sales 129
  4. Accountant はクエリをもう一度実行できます。また、トランザクションが終了していないため、新しいローを認識しません。

    SELECT *
    FROM Departments
    ORDER BY DepartmentID;
    DepartmentID DepartmentName DepartmentHeadID
    100 R & D 501
    200 Sales 902
    300 Finance 1293
    400 Marketing 1576
    500 Shipping 703
  5. Sales Manager は、大企業を対象にした営業活動を行う新たな部署を追加したいと思っています。Sales Manager のウィンドウで次のコマンドを実行します。

    INSERT INTO Departments
     (DepartmentID, DepartmentName, DepartmentHeadID)
       VALUES(700, 'Major Account Sales', 902);

    Accountant がスナップショット・アイソレーションを使用しているため、Sales Manager による変更はブロックされません。

  6. Sales Manager がデータベースにコミットした変更を認識するために、Accountant はスナップショット・アイソレーションを終了する必要があります。

    COMMIT;
       SELECT * FROM Departments
       ORDER BY DepartmentID;

    Accountant は Foreign Sales 部署を認識するようになりました。ただし、Major Account Sales 部署は認識しません。

    DepartmentID DepartmentName DepartmentHeadID
    100 R & D 501
    200 Sales 902
    300 Finance 1293
    400 Marketing 1576
    500 Shipping 703
    600 Foreign Sales 129
  7. SQL Anywhere サンプル・データベースが変更されないようにするため、Major Account Sales 部署のローを挿入する未完了トランザクションをロールバックし、2 つ目のトランザクションを使用して Foreign Sales 部署を削除してください。

    1. Sales Manager のウィンドウで次のコマンドを実行し、最後の未完了トランザクションをロールバックします。

      ROLLBACK;
    2. Sales Manager のウィンドウで次の 2 つの文を実行し、先に挿入したローを削除し、この操作をコミットします。

      DELETE FROM Departments
      WHERE DepartmentID = 600;
      COMMIT;