目次へ

解答例 - 実習課題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();
        }
    }
}

▼データベースの指定

JDBC 1章 実習課題1を参照

▼データベース例(実行前)

 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
  ===============

↑このページの先頭へ

こちらもチェック!

PR
  • XMLDB.jp