解答例 - 実習課題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 ===============

