3. JDBCアプリケーションの開発

3.1. プログラミング・開発ガイド

JDBCデータソースを利用するアプリケーションの動作環境とプログラミング方法について説明します。
JDBCアプリケーションを作成するには次のAPIを利用します。
各APIの詳細は、[ リファレンス集 開発編(共通) > 3. リソース > 3.1. JDBCデータソース ]などを参照してください。
以降では、次のプログラミング内容について説明します。

3.1.1. JDBCアプリケーションの動作環境について

JDBCデータソースを利用するアプリケーションを動作させるための環境設定について説明します。

3.1.1.1. 実行環境(サーバ)

3.1.1.2. 実行環境(クライアント)

JDBCドライバベンダのライブラリの詳細は、 [ リファレンス集 運用管理・設定編 > 1. コンフィグレーション(設定一覧) > 1.8. JDBCデータソース > 1.8.12. クラスパス設定 ] を参照してください。

3.1.2. JDBCアプリケーションでのimport文について

JDBCアプリケーションでは、必要に応じて、次のimport文を記述してください。

3.1.2.1. コーディング例

// JDBCのインタフェース
import java.sql.*;
import javax.sql.DataSource;
 
// JNDIのインタフェース
import javax.naming.*;
 
// JDBCデータソース固有のインタフェース
import jp.co.nec.WebOTX.WODataSource;
import com.nec.wojdbc.WOConnectionWrapper;

3.1.3. 一般的なJDBCコネクションの取得方法

標準のJNDIとJDBCのインタフェースを利用してJDBCコネクションを取得します。 JTAのトランザクションに参加するかどうかに関わらず、同じ記述になります。

3.1.3.1. コーディング例

InitialContext ic;
DataSource ds;
public void method_init ()
{
    try {
        // JDBC データソースの取得
        ic = new InitialContext();
        ds = (DataSource)ic.lookup("jdbc/Oracle");
    } catch(Exception ex) {
        ex.printStackTrace();
    }
}
public void method_1 ()
{
    Connection conn = null;
    try {
        // JDBC コネクションの取得
        conn = ds.getConnection();
 
        // SQL 命令の実行
    } catch(Exception ex) {
        ex.printStackTrace();
    } finally {
        if ( conn != null ) {
            try {
                // JDBC コネクションのクローズ
                conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

3.1.3.2. JDBCデータソースの取得

予め、JNDIサーバに登録済みのJDBCデータソースを取得します。
JDBCデータソースの取得は、時間がかかる処理ですので、何度も行わないようにしてください。
JNDIサーバにJDBCデータソースを登録するためには、 create-jdbc-datasource コマンドか dsadmコマンドを使用します。詳細は、 [ リファレンス集 運用管理・設定編 > 4. 運用管理コマンドリファレンス ] を参照してください。

3.1.3.3. JDBCコネクションの取得

JDBCデータソースからJDBCコネクションを取得します。
アプリケーションは、接続先データベース固有の情報を意識する必要がありません。JDBCデータソース内にプールされているJDBCコネクションがあれば、そのJDBCコネクションが直ちに返却されます。
JDBCデータソースによるデータベースサーバの障害監視(checkServerOptionプロパティで設定)や接続リトライ(connectRetryMaxとconnectRetryIntervalプロパティで設定)は、JDBCコネクション取得時に行われます。このため、毎回JDBCコネクションを取得するように記述すると、再接続処理を別途記述する必要がなくなります。

Memo
JDBCデータソースのプロパティの詳細は、 [ リファレンス集 運用管理・設定編 > 1. コンフィグレーション(設定一覧) > 1.8. JDBCデータソース ] を参照してください。

3.1.3.4. JDBCコネクションのクローズ

取得したJDBCコネクションは、必ず、クローズするようにしてください。
JDBCデータソースのcheckGarbageOptionプロパティにdebugを指定すると、クローズ漏れの有無、および、クローズ漏れが発生した場所を確認することができます。 コネクションのリークを検証する場合にご利用ください。

3.1.4. AutoCommitモードの変更方法

複数の更新系SQL命令を実行する場合に、AutoCommitモードを変更します。
複数のSQL命令を実行した後、まとめてコミットすることで、性能を改善することができます。また、異常が発生した場合、全ての更新内容をロールバックすることができますので、データの不整合が発生しません。
AutoCommitモードは、JTAのトランザクションを実行しない場合に限り、変更することができます。

3.1.4.1. コーディング例

DataSource ds;
public void method_2 ()
{
    Connection conn = null;
    try {
        // JDBC コネクションの取得
        conn = ds.getConnection();
        // AutoCommit モードの変更
        conn.setAutoCommit(false);

        // SQL命令の実行
 
        // 更新内容のコミット
        conn.commit();
    } catch(Exception ex) {
        if ( conn != null ) {
            try {
                // 更新内容のロールバック
                conn.rollback();
            } catch (Exception e) {}
        }
        ex.printStackTrace();
    } finally {
        if ( conn != null ) {
            try{
                // JDBC コネクションのクローズ
                conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

3.1.4.2. AutoCommitモードの変更

アプリケーションで、複数の更新系SQL命令を実行する場合は、AutoCommitモードをfalseに変更してください。または、JDBCデータソースのdefaultAutoCommitプロパティをfalseに変更してください。
参照系SQL命令だけを実行する場合や、更新系SQL命令を1つだけ実行する場合、AutoCommitモードを変更する必要はありません。

Memo
JDBCデータソースのプロパティの詳細は、 [ リファレンス集 運用管理・設定編 > 1. コンフィグレーション(設定一覧) > 1.8. JDBCデータソース ] を参照してください。

3.1.4.3. 更新内容のコミット

更新系SQL命令を実行した後は、必ず、更新内容のコミットを行ってください。あるいは、異常を検知した場合には、必ず、更新内容をロールバックしてください。


3.1.5. JTAのトランザクションで、同時に複数のJDBCコネクションを利用する方法

JTAのトランザクションで、同一データベースとのJDBCコネクションを、同時に複数取得するための方法について説明します。

3.1.5.1. コーディング例

DataSource ds;
public void method_3 ()
{
    Connection conn1 = null;
    try {
        // JDBC コネクションの取得(1)
        conn1 = ds.getConnection();
        // EJBのメソッド呼び出し
        method_4();

        // SQL命令の実行
    } catch(Exception ex) {
        ex.printStackTrace();
    } finally{
         if ( conn1 != null ) {
             try{
                // JDBC コネクションのクローズ(1)
                conn1.close();
             } catch (Exception e) {
                 e.printStackTrace();
             }
         }
    }
}
public void method_4 ()
{   
    Connection conn2 = null;
    try {
        // JDBC コネクションの取得(2)
        conn2 = ds.getConnection();

        // SQL命令の実行
    } catch(Exception ex) {
        ex.printStackTrace();
    } finally {
        if ( conn2 != null ) {
            try{
                // JDBC コネクションのクローズ(2)
                conn2.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

3.1.5.2. JDBCコネクションの取得

2つ目以降のJDBCコネクションを、ローカルメソッドやアプリケーションの共通クラスのメソッド内で呼び出したい場合には、useOneConnectionPerTransactionプロパティにtrueを設定してください。

Memo
JDBCデータソースのプロパティの詳細は、 [ リファレンス集 運用管理・設定編 > 1. コンフィグレーション(設定一覧) > 1.8. JDBCデータソース ] を参照してください。

3.1.5.3. JDBCコネクションのクローズ

トランザクション内で最初に取得したJDBCコネクションのクローズは、必ず、最後に行ってください。


3.1.6. JDBCドライバベンダのJDBCコネクションの取得方法

JDBCドライバベンダ固有のAPIを呼び出すために、JDBCドライバベンダのJDBCコネクションクラスを取得します。

3.1.6.1. コーディング例(WebOTX固有インタフェースの利用例)

DataSource ds;
public void method_5 ()
{
    Connection conn = null;
    try {
        // JDBCドライバベンダのJDBCコネクション
        Connection realconn = null;
        // JDBC コネクションの取得
        conn = ds.getConnection();
        // JDBCドライバベンダのJDBCコネクションの取得
        if (conn instanceof com.nec.wojdbc.WOConnectionWrapper) {
            WOConnectionWrapper wocon = (com.nec.wojdbc.WOConnectionWrapper)conn;
            realconn = wocon.getRealConnection();
        }
        else {
           realconn = conn;
        }
        // JDBC ドライバベンダ固有のAPI呼び出し
//     try{   
//         String tmzone = ((oracle.jdbc.OracleConnection)realconn).getSessionTimeZone();
//         System.out.println("Session TimeZone: " + tmzone );
//      } catch(Throwable t ){
//         System.out.println("getSessionTimeZone() not supported. :" + t );
//      }
 
        // SQL命令の実行
    } catch(Exception ex) {
        ex.printStackTrace();
    } finally {
        if ( conn != null ) {
            try {
                // JDBC コネクションのクローズ
                conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

3.1.6.2. JDBCドライバベンダのJDBCコネクションの取得

getConnectionメソッドは、JDBCドライバベンダのJDBCコネクションクラスを直接返却する場合があります。このため、キャストを行う前に、instanceofでキャストできるかどうかを確認してください。
getConnectionメソッドは、次の条件を全て満たす場合にJDBCドライバベンダのJDBCコネクションクラスを直接返却します。それ以外の場合には、JDBCデータソース固有のクラスを返却します。これらの条件を満たすかどうかはっきりしていて、今後、変更がないのであれば、instanceofでの確認を省略することができます。
JDBCデータソースでは、JDBCコネクションのほか、JDBCステートメントのラッパークラスを実装しています。そのほかのJDBCリザルトセットなどは、全て、JDBCドライバベンダのクラスを返却します。

Memo
JDBCデータソースのプロパティの詳細は、 [ リファレンス集 運用管理・設定編 > 1. コンフィグレーション(設定一覧) > 1.8. JDBCデータソース ] を参照してください。

3.1.6.3. JDBCコネクションのクローズ

JDBCドライバベンダのJDBCコネクションのクローズメソッドは、直接呼び出さないでください。

3.1.6.4. コーディング例(JDBC4.0の利用例)

DataSource ds;
public void method_5 ()
{
    Connection conn = null;
    Statement stmt = null;
    try {
        // JDBC ドライバベンダのJDBCコネクション
        oracle.jdbc.OracleConnection realconn = null;
        // JDBC コネクションの取得
        conn = ds.getConnection();
        // JDBC ドライバベンダのJDBCコネクションの取得
        Class cl = Class.forName(“oracle.jdbc.OracleConnection”);
        if (conn.isWrapperFor(cl)) {
           realconn = conn.unwrap(cl);
        }
         // JDBC ドライバベンダ固有のAPI呼び出し
//     try{   
//         String tmzone = realconn.getSessionTimeZone();
//         System.out.println("Session TimeZone: " + tmzone );
//      } catch(Throwable t ){
//         System.out.println("getSessionTimeZone() not supported. :" + t );
//      }

        // JDBC ドライバベンダのJDBCステートメント
        oracle.jdbc.driver.OracleStatement realstmt = null;
        // JDBC ステートメントの取得
        stmt = conn.createStatement();
        // JDBC ドライバベンダのJDBCステートメントの取得
        cl = Class.forName(“oracle.jdbc.driver.OracleStatement”);
        if (stmt.isWrapperFor(cl)) {
           realstmt = stmt.unwrap(cl);
        }
 
        // SQL命令の実行

    } catch(Exception ex) {
        ex.printStackTrace();
    } finally {
        if ( stmt != null ) {
           try {
               // JDBC ステートメントのクローズ
                stmt.close();
            } catch (Exception e) {  
                e.printStackTrace();
            }
        }
        if ( conn != null ) {
           try {
               // JDBC コネクションのクローズ
                conn.close();
            } catch (Exception e) {  
                e.printStackTrace();
            }
        }
    }
}

3.1.6.5. JDBCドライバベンダのJDBCコネクションの取得

WebOTX固有インターフェイスのcom.nec.wojdbc.WOConnectionWrapperを使用することなく、JDBCコネクションクラスのisWrapperForメソッドやunwrapメソッドを利用することで、 JDBCドライバベンダのJDBCコネクションクラスを取得することができます。

3.1.6.6. JDBCドライバベンダのJDBCステートメントの取得

JDBCコネクションと同様に、JDBCステートメントクラスのisWrapperForメソッドやunwrapメソッドを利用することで、JDBCドライバベンダのJDBCステートメントクラスを取得することができます。

3.1.6.7. JDBCコネクションのクローズ

JDBCドライバベンダのJDBCコネクションのクローズメソッドは、直接呼び出さないでください。


3.1.7. JNDIを利用せずにJDBCデータソースを利用する方法

JNDIサーバを利用できない環境でJDBCデータソースを利用する場合、アプリケーションでjp.co.nec.WebOTX.WODataSourceクラスインスタンスを生成します。

3.1.7.1. コーディング例

DataSource ds;
public void method_5 ()
{
    Connection conn = null;
    try {
        // WODataSource クラスインスタンスの作成
        WODataSource wods = new WODataSource();
        // プロパティ値の取得
        String filename = System.getProperty("MY_PROPERTY_FILE_NAME");
        java.util.Properties props = new java.util.Properties();
        java.io.FileInputStream fin = new java.io.FileInputStream(filename);
        try {
            props.load(fin);
        } finally {
            if (fin != null) fin.close();
        }
        // プロパティ値の設定
        wods.setDataSourceName(props.getProperty("dataSourceName"));
        wods.setDataSourceType(props.getProperty("dataSourceType"));
        wods.setUserName(props.getProperty("userName"));
        wods.setPassword(props.getProperty("password"));
        wods.setUseJTA(Boolean.valueOf(props.getProperty("useJTA")).booleanValue());
        ds = wods;
        // JDBCコネクションの取得
        conn = ds.getConnection();
 
        // SQL命令の実行
    } catch(Exception ex) {
        ex.printStackTrace();
    } finally {
        if ( conn != null ) {
            try {
                // JDBC コネクションのクローズ
                conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

3.1.7.2. WODataSourceクラスインスタンスの作成

WODataSourceクラスインスタンスを直接生成します。
WODataSourceクラスインスタンスを何度も生成することは非効率ですので、クラスインスタンスを使い回すようにしてください。

3.1.7.3. プロパティ値の取得

プロパティ値として固定値を記述するのではなく、例えば、システムプロパティやプロパティファイルを使用して入手するようにし、構成変更等によるプログラム修正が必要にならないようにしてください。

3.1.7.4. プロパティ値の設定

データベースとの接続を行うために必要なプロパティ値を設定します。プロパティ値を設定するためのAPIは、 [ リファレンス集 開発編(共通) > 3. リソース > 3.1. JDBCデータソース ]を参照してください。
プロパティ値の設定が完了した後は、標準のjavax.sql.DataSourceインタフェースクラスとして利用することをお勧めします。

Memo
JDBCデータソースのプロパティの詳細は、 [ リファレンス集 運用管理・設定編 > 1. コンフィグレーション(設定一覧) > 1.8. JDBCデータソース ] を参照してください。