解答例 - 実習課題3 - 3.トランザクション処理
(実習課題3)
以下のプログラムを作成し、「READ_COMMITTED」レベルでは「ノンリピータブルリード」「ファントムインサート」が発生する事を、「SERIALIZABLE」では発生しない事を確認しなさい。
- 「product」テーブルで実行したクエリーの結果を表示するコンソールプログラム。
- 同じselect文を2度実行して、一回目と二回目で実行結果が同じか異なるかで、「ノンリピータブルリード」「ファントムインサート」が発生しているかどうか確認する。
- 一回目と二回目の処理が続けて実行されないように、間にコンソールからの入力を受け付けるようにプログラムを作成する事。これによりコンソールからの入力が無ければ二回目の処理は開始されないようになる。
- 作成したプログラムの実行時には、一回目と二回目の間にデータベースで直接「product」テーブルを編集して、「ノンリピータブルリード」「ファントムインサート」が発生する条件を整えること。
- 直接「product」テーブルを編集する際、どのようなクエリーを実行したか、また結果のどの辺りが「ノンリピータブルリード」「ファントムインサート」なのかも明示する事。
解答例
▼データベースアクセス用クラスのソース
package com.techscore.jdbc.chapter3.exercise3; /** * ProductDAO.java * TECHSCORE JDBC3章 実習課題3 * * Copyright (c) 2004 Four-Dimensional Data, Inc. */ import java.sql.Connection; import java.sql.ResultSet; import java.sql.Statement; import java.sql.SQLException; import java.sql.DriverManager; public class ProductDAO{ public final int READ_COMMITED=0; public final int SERIALIZABLE=1; private Statement statement = null; private Connection conn = null; private Connection getConnection() throws SQLException,ClassNotFoundException{ Class.forName("org.postgresql.Driver"); conn = DriverManager.getConnection("jdbc:postgresql://dbserver:5432/Training" ,"postgres" //ユーザ名 ,""); //パスワード conn.setAutoCommit(false); //自動コミットモード解除 return conn; } public int loadMaxPrice(int TransactionIsolation) throws SQLException,ClassNotFoundException{ conn = getConnection(); if (TransactionIsolation ==SERIALIZABLE){ conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE); } statement = conn.createStatement(); int price = excecuteCommand(); return price; } public int excecuteCommand() throws SQLException{ int price = 0; final String sql = "select max(price) from product"; ResultSet result = statement.executeQuery(sql); while (result.next()){ price = result.getInt(1); } result.close(); return price; } public void finishTransaction() throws SQLException{ try{ statement.close(); }finally{ if (conn != null){ conn.close(); } } } }
▼データ挿入測定クラスのソース
package com.techscore.jdbc.chapter3.exercise3; /** * TestHappenTrouble.java * TECHSCORE JDBC3章 実習課題3 * * Copyright (c) 2004 Four-Dimensional Data, Inc. */ import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.sql.SQLException; public class TestHappenedTrouble { public static void main(String[] args) { int TransactionIsolation; try { ProductDAO productDAO = new ProductDAO(); int price = 0; if ("s".equals(args[0])) { System.out.println("SERIALIZABLEレベルを指定"); TransactionIsolation = productDAO.SERIALIZABLE; } else { System.out.println("READ_COMMITTEDレベルを指定"); TransactionIsolation = productDAO.READ_COMMITED; } price = productDAO.loadMaxPrice(TransactionIsolation); System.out.println("1回目の製品番号MAX価格:" + price); InputStream input = System.in; DataInputStream ins = new DataInputStream(input); System.out.println("価格を変更してEnterを押してください。"); System.out.println("「ノンリピータブルリード」を発生させたい場合はUpdateを"); System.out.println("「ファントムインサート」を発生させたい場合はInsertを"); System.out.println("使用してMAX価格(price)を変更してください。"); String dummy = ins.readLine(); price = productDAO.excecuteCommand(); productDAO.finishTransaction(); System.out.println("2回目の製品番号MAX価格:" + price); }catch(SQLException e){ e.printStackTrace(); }catch(ClassNotFoundException e){ e.printStackTrace(); }catch (ArrayIndexOutOfBoundsException e) { System.out.println("TransactionIsolationを指定してください"); System.out.println("S:SERIALIZABLE R:READ_COMMITTED"); }catch (IOException e) { e.printStackTrace(); } } }
▼データベースの指定
▼データベース例(実行前)
p_num | p_name | type | price -------+--------------+-------+------- 101 | Accort | sedan | 230 102 | Accort Wagon | RV | 280 104 | Hodyssey | RV | 280 105 | Shtep Wagon | RV | 200 106 | Accort | sedan | 230 107 | Accort | sedan | 290 103 | Insphire | sedan | 500 (7 rows)
▼実行例:「ノンリピータブルリード」
0.実行内容 =============== 1回目の製品番号MAX価格:500 価格を変更してEnterを押してください。 「ノンリピータブルリード」を発生させたい場合はUpdateを 「ファントムインサート」を発生させたい場合はInsertを 使用してMAX価格(price)を変更してください。 ●UPDATE product_f SET price=600 WHERE p_num=103; を入力しEnter =============== 1.READ_COMMITEDレベル指定 ・実行結果表示 =============== 2回目の製品番号MAX価格:600 =============== 2.SERIARIZEレベル指定 ・実行結果表示 =============== 2回目の製品番号MAX価格:500 ===============
▼実行例:「ファントムインサート」
0.実行内容 =============== 1回目の製品番号MAX価格:500 価格を変更してEnterを押してください。 「ノンリピータブルリード」を発生させたい場合はUpdateを 「ファントムインサート」を発生させたい場合はInsertを 使用してMAX価格(price)を変更してください。 ●insert into product_f values(108,'TestName','TestType',600); を入力しEnter =============== 1.READ_COMMITEDレベル指定 実行結果表示 =============== 2回目の製品番号MAX価格:600 =============== 2.SERIARIZEレベル指定 実行結果表示 =============== 2回目の製品番号MAX価格:500 ===============