QZDASOINIT での SQL処理の一部としてコマンドを実行したい

JDBC プログラムを DB2 for IBM i で実行する際には QZDASOINIT というジョブで(ほとんどのケースでは)実行されるわけですが、このジョブの属性を変えたい、と思ったことはありませんか??

また、その JDBC プログラムの実行の途中で CL コマンドを実行させたい、と考えたことはありませんか??

どちらも実際にはカンタンにできるんですね。


JDBC 処理の中で SQL 実行前に/後に/間に CL コマンドを実行したいときには

JDBC トランザクションの一部としてストアド・プロシージャを実行することが可能です。SQL の実行前でも後でも、一連の SQL の実行の途中でもストアド・プロシージャを CALL して実行することができますよね。

ここで、あることを思い出してほしいんですね。

以前「QCMDEXC ストアド・プロシージャ」で紹介したように、昔からある QCMDEXC が SQLストアド・プロシージャとして実行できるようになっています。V5R4 からの機能です。RPG の中から CL コマンドを実行したい場合によく使われている機能ですね。System API 登場以前は、この QCMDEXC しか RPG 処理の一部としてコマンドを実行する方法はありませんでした。

この QCMDEXCプロシージャは、V7R1 TR7 以降はさらに使いやすくなっています。何かと面倒だった引数としてのコマンド文字列の長さの指定が必要なくなっているんですね。(「QSYS2.QCMDEXC() procedure no longer requires a command length」)

この、JDBC プログラムの中でストアド・プロシージャが使える、ということと、QCMDEXCプロシージャで CL コマンドをが実行できる、という二点を組み合わせればいいわけですね。QCMDEXCプロシージャで実行できる CL コマンドは、JDBC プログラムの中で、ストアド・プロシージャが実行できる場面であれば自由に実行できる、というわけです。

JDBC でストアド・プロシージャの実行

ストアド・プロシージャの実行はカンタンです。

↓のように、CallableStatement オブジェクトとしてストアド・プロシージャの呼び出しを準備し、

CallableStatement cstmt = conn.prepareCall("CALL QSYS2.QCMDEXC (?)");

コマンド文字列を引数としてセットし、

cstmt.setString(1, "CHGJOB RUNPTY(45)");

実行します。

cstmt.execute()

JDBC 処理内での CL コマンド実行のサンプル

こちらがサンプルの全文です。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.CallableStatement;
import com.ibm.as400.access.*;

public class JDBCwithCommands {

  public static void main(String[] args) {
    Connection conn = null;
    CallableStatement cstmt = null;
    Statement stmt = null;
    ResultSet rs = null;
    try{
      //接続処理
      Class.forName("com.ibm.as400.access.AS400JDBCDriver");
      conn = DriverManager.getConnection(
          "jdbc:as400://system/SAMPLE"
          ,"user","password");
      System.out.println("接続されました");

      //コマンドの実行準備
      cstmt = conn.prepareCall("CALL QSYS2.QCMDEXC (?)");

      //コマンドのセットと実行
      cstmt.setString(1, "CHGJOB RUNPTY(45)");
      //V7R1 TR7 以前では↓のようにする
      //String cmd = "CALL QSYS.QCMDEXC ('CHGJOB RUNPTY(45)', 0000000017.00000)";
      //cstmt = conn.prepareCall(cmd);
      cstmt.execute();
      cstmt.setString(1, "OVRDBF FILE(EMPLOYEE) TOFILE(SAMPLEDB/EMPLOYEE) OVRSCOPE(*JOB)");      
      cstmt.execute();

      //SQL の準備
      stmt = conn.createStatement();

      //SQL のセットと実行
      String sql = "SELECT FIRSTNME, LASTNAME, SALARY" +
                   "  FROM EMPLOYEE" ;
      rs = stmt.executeQuery(sql);
      
      //実行結果の表示
      while(rs.next()){
        String FirstName = rs.getString("FIRSTNME");
        String LastName = rs.getString("LASTNAME");
        int salary = rs.getInt("SALARY");
        System.out.print("名前:" + FirstName + ' ' + LastName + "\t" + "\t");
        System.out.println("給料:" + salary);
      }
      
      //コマンドのセットと実行
      cstmt.setString(1, "DLYJOB DLY(30)");
      cstmt.execute();

      //クローズ処理
      rs.close();
      stmt.close();
      cstmt.close(); 
      
    }catch(ClassNotFoundException e){ 
      e.printStackTrace();
    }catch(SQLException e){
      try{
        //問題が起きたときはジョブログの出力
        if(cstmt!= null) {
          cstmt.setString(1, "DSPJOBLOG OUTPUT(*PRINT)");
          cstmt.execute();
           }
          }catch(SQLException se) { se.printStackTrace(); } 
      System.err.println("DB2 for i エラーコード:" + e.getErrorCode());
      System.err.println("SQLState コード:" + e.getSQLState());
      System.err.println("エラーメッセージ:" + e.getMessage());
      e.printStackTrace();
    }
    finally{
      //Statement、CallableStatement、Connectionオブジェクトのクローズ処理
      try{ 
        if(stmt!= null) stmt.close();
        if(cstmt!= null) cstmt.close();
      }catch(SQLException e){
        e.printStackTrace();
      }
      //Connectionオブジェクトのクローズ処理
      try{ 
        if(conn != null) conn.close();
        System.out.println("切断しました");
      }catch(SQLException e){
        e.printStackTrace();
      }
    
}
  }
}

SQL 処理の実行前に CHGJOB で実行優先順位を下げています。重たい処理なのでオンラインに影響を与えたくない、などという場合を想定してみました。
また、OVRDBF などもできるよ、ということで、テーブルを別のテーブルにオーバーライドするようにしています。
SQL 実行後に DLYJOB を実行してみました。これで様子の観察がカンタンにできますね?!
問題(Exception)発生時にジョブログを取得する処理も入れてあります。

実行例

実行してみましょう。

実行優先順位が変更されていることが確認できますね。

テーブルのオーバーライドも実行されていることがわかります。

SQL処理が終了してコネクションが開放されるとCHGJOBはもとに戻っていることがわかります。

DLTOVR コマンドも必要ありません。オーバーライドも、コネクション開放と共に削除されます。

ポイント

他にも、SQL 実行前に CHGPF コマンドでテーブルを SSD に持ってくる、などいろんなことができるでしょう。

CHGJOB コマンドや OVRxxx コマンドの結果はコネクション開放時にもとに戻りますが、CHGPF コマンドなどは実行してしまったら当然のことながら勝手にもとには戻りません。一時変更ではありませんね。
きちんと SQL 実行後の処理でもとに戻すようにしましょう。

[Top Pageに戻る]

Ads by TOK2