3.3. トランザクションの隔離レベル(transaction isolation level)
トランザクションは他のトランザクションから影響を受けないために、操作の対象とするテーブル・行などをロックします。どの程度、ロックするかによって4種類のレベルが定義されています。レベルは、複数のトランザクションが同時並行処理された場合に起こりうる4つの問題に応じて分けられています。以下の表は、4つのレベルと4つの問題が発生する可能性についてまとめた表です。ここではそれぞれの問題の詳細については省略します。
隔離レベル | ロストアップデート | ダーティリード | ノンリピータブルリード | ファントムインサート |
---|---|---|---|---|
READ UNCOMMITTED | × | ○ | ○ | ○ |
READ COMMITTED | × | × | ○ | ○ |
REPEATABLE READ | × | × | × | ○ |
SERIALIZABLE | × | × | × | × |
例えば「READ UNCOMMITTED」レベルでは「ロストアップデート」は生じませんが、他は生じる可能性があります。「SERIALIZABLE」レベルでは全て発生しません。
Javaでトランザクションの隔離レベルを取得・設定するには、「Connection」の「getTransactionIsolation」「setTransactionIsolation」を使用します。引数および返り値の判定には、「Connection」のクラス変数「TRANSACTION_???」を使用するのが適当です。それぞれの4つのレベルに対応して4つのクラス変数が定義されています。例えば「SERIALIZABLE」レベルにするためには以下のようにします。
connection.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
全ての隔離レベルがサポートされているわけではありません。データベースによってサポートされているレベルに違いがあります。データベースが任意の隔離レベルをサポートしているかどうか調べるには、「DatabaseMetaData」の「supportsTransactionIsolationLevel」メソッドを使用します。「Connection」の「getMetaData」メソッドを使用すれば「DatabaseMetaData」オブジェクトを取得できます。
DatabaseMetaData metaData=connection.getMetaData(); boolean support=metaData.supportsTransactionIsolationLevel(Connection.TRANSACTION_SERIALIZABLE);
以上はトランザクションのSERIALIZABLEレベルがサポートされているか調べています。他に、「DatabaseMetaData」はどのようなSQL文をサポートしているか調べる事ができます。ちなみにPostgreSQLでは、「READ_COMMITTED」「SERIALIZABLE」の2つの隔離レベルをサポートしています。デフォルトは「READ_COMMITTED」です。
(実習課題3)
以下のプログラムを作成し、「READ_COMMITTED」レベルでは「ノンリピータブルリード」「ファントムインサート」が発生する事を、「SERIALIZABLE」では発生しない事を確認しなさい。
- 「product」テーブルで実行したクエリーの結果を表示するコンソールプログラム。
- 同じselect文を2度実行して、一回目と二回目で実行結果が同じか異なるかで、「ノンリピータブルリード」「ファントムインサート」が発生しているかどうか確認する。
- 一回目と二回目の処理が続けて実行されないように、間にコンソールからの入力を受け付けるようにプログラムを作成する事。これによりコンソールからの入力が無ければ二回目の処理は開始されないようになる。
- 作成したプログラムの実行時には、一回目と二回目の間にデータベースで直接「product」テーブルを編集して、「ノンリピータブルリード」「ファントムインサート」が発生する条件を整えること。
- 直接「product」テーブルを編集する際、どのようなクエリーを実行したか、また結果のどの辺りが「ノンリピータブルリード」「ファントムインサート」なのかも明示する事。