ストアドからjavaのクラスを呼ぶ [ apache Derby (JavaDB) on winXP

使ったもの

java (SE) 1.5.0_11

DERBY_HOME、CLASSPATH 設定

C:\> set DERBY_HOME=C:\INSTALL_DIR
C:\> set CLASSPATH=%DERBY_HOME%\lib\derby.jar;%DERBY_HOME%\lib\derbyclient.jar;%DERBY_HOME%\lib\derbytools.jar;%DERBY_HOME%\lib\derbynet.jar;%DERBY_HOME%\lib\derbyrun.jar;%CLASSPATH%

INSTALL_DIR*1

db スキーマの保存ディレクトリを作成

C:\> mkdir DB_DIR

DB_DIR (好きな場所に。derby.system.home= に指定するパス)

設定ファイル(ファイル名::derby.properties)

## 認証の設定 ##
derby.connection.requireAuthentication=true
derby.authentication.propvider=BUILTIN

## ユーザ設定 ##
derby.database.fullAccessUsers=admin

## ユーザのパスワード設定 ##
derby.user.admin=admin

## ログの設定 ##
derby.infolog.append=append

DB_DIR 以下に置く
その他のプロパティ
ドキュメント全般

サーバ起動

C:\> java -Dderby.system.home=C:\DB_DIR org.apache.derby.drda.NetworkServerControl start
セキュリティーマネージャーが Basic サーバーセキュリティーポリシーを使用してインストールされました。
Apache Derby Network Server - YYYYY-MM-DD HH:MM:SS.937 GMT に 10.4.1.3 - (648739) が開始され、ポート 1527 で接続を受け入れる準備ができました。

コンソール(ij)起動

C:\> java -Dderby.system.home=C:\DB_DIR  org.apache.derby.tools.ij
ij バージョン 10.4
ij>_

コンソールからDB接続

ij> connect 'jdbc:derby://localhost:1527/test_db;user=admin;password=admin;create=true';

create=true*2
終了 ij > disconnrct;

テーブル、データの作成

ij>create table m_user (
     id   int not null,
     name varchar(32)
   );
0 行が挿入/更新/削除されました

ij>INSERT INTO m_user(id,name) VALUES(1,'nurai');
1 行が挿入/更新/削除されました

ij>SELECT * FROM m_user;
ID         |NAME
--------------------------------------------
1          |nurai

1 行が選択されました

java から接続

DBConnect.java
import java.sql.*;

public class DBConnect {
    private static String host    = "localhost";
    private static String user    = "admin";
    private static String passwd  = "admin";
    private static Connection con = null;

    public static Connection getConnect(String dbSchm) throws SQLException{
	try{
            Class.forName("org.apache.derby.jdbc.ClientDriver");
            String url = "jdbc:derby://" + host + ":1527/" + dbSchm;
            con = DriverManager.getConnection(url,user,passwd);
        }
        catch(ClassNotFoundException e){
            System.err.println(e.getMessage());
            e.printStackTrace();
        }
        catch(SQLException e){
            throw e;
        }
        return con;
    }
}
TestClinet.java
import java.sql.*;

public class TestClient {
    public static void main(String[] args) {

        Connection con          = null;
        Statement stmt          = null;
        CallableStatement cstmt = null;
        ResultSet rs            = null;

        try{

            // test_db.m_user の内容を表示(接続確認)
            con  = DBConnect.getConnect("test_db");
            stmt = con.createStatement();
            rs   = stmt.executeQuery("SELECT * FROM M_USER");
            while(rs.next()){
                System.out.println("  id::" + rs.getInt(1));
                System.out.println("name::" + rs.getString(2));
            }
        }
        catch(SQLException e){
            System.err.println(e.getMessage());
            e.printStackTrace();
        }
        finally{
            try{
                if (rs != null) rs.close();
                if (cstmt != null) stmt.close();
                if (con != null) con.close();
            }
            catch(SQLException e){
                System.err.println(e.getMessage());
                e.printStackTrace();
            }
        }
    }
}
コンパイル & テスト
C:\src>javac DBConnect.java
C:\src>javac TestClient.java

C:\src>java TestClient
  id::1
name::nurai

プロシージャクラスの作成

MyProcedure.java
import java.sql.*;

public class MyProcedure {

    public static void addFirstName(int id, String firstName, ResultSet[] resultSet) throws SQLException {

        Connection con  = null;
        Statement  stmt = null;
        ResultSet  rs   = null;

        try{
            con = DriverManager.getConnection("jdbc:default:connection");
            stmt = con.createStatement();
            String qryString = "SELECT name FROM M_USER WHERE id=" + id;
            rs   = stmt.executeQuery(qryString);
            if(rs.next()){
                String addFirstName = rs.getString(1) + " " + firstName;
                System.out.println(addFirstName);
                stmt.executeUpdate("UPDATE M_USER SET name='" + addFirstName +"'");
                resultSet[0] = stmt.executeQuery(qryString);
            }
            return;
        }
        catch(SQLException e){
            System.err.println(e.getMessage());
            e.printStackTrace();
        }
        finally{
            try{
                if(con  != null) con.close();
            }
            catch(SQLException e){
                System.err.println(e.getMessage());
                e.printStackTrace();
            }
        }
    }
}

プロシージャの作成

ij> DROP PROCEDURE M_USER.ADD_FIRST_NAME;
CREATE PROCEDURE M_USER.ADD_FIRST_NAME(
  id           INTEGER,
  firstName    VARCHAR(32)
)
MODIFIES SQL DATA
DYNAMIC RESULT SETS 1
PARAMETER STYLE JAVA
LANGUAGE JAVA
EXTERNAL NAME
'MyProcedure.addFirstName'
;
dbサーバにクラスパスの再設定を行い、再起動
C:\> set CLASSPATH="C:\src";%CLASSPATH%
C:\> java -Dderby.system.home=C:\DB_DIR org.apache.derby.drda.NetworkServerControl start
セキュリティーマネージャーが Basic サーバーセキュリティーポリシーを使用してインストールされました。
Apache Derby Network Server - YYYYY-MM-DD HH:MM:SS.937 GMT に 10.4.1.3 - (648739) が開始され、ポート 1527 で接続を受け入れる準備ができました。

MyProcedure の場所を derby に教える。

TestClinet.java を修正

import java.sql.*;

public class TestClient {
    public static void main(String[] args) {

        Connection con          = null;
        Statement stmt          = null;
        CallableStatement cstmt = null;
        ResultSet rs            = null;

        try{

            // test_db.m_user の内容を表示(接続確認)
            con  = DBConnect.getConnect("test_db");
            stmt = con.createStatement();
            rs   = stmt.executeQuery("SELECT * FROM M_USER");
            while(rs.next()){
                System.out.println("  id::" + rs.getInt(1));
                System.out.println("name::" + rs.getString(2));
            }

            //  ストアドプロシージャの呼び出し
            cstmt = con.prepareCall("{call M_USER.ADD_FIRST_NAME(?, ?)}");
            cstmt.setInt(1,1);
            cstmt.setString(2,"naoki");
            cstmt.execute();
            rs    = cstmt.getResultSet();
            while(rs.next()){
                System.out.println("=====");
                System.out.println("addFirstName::" + rs.getString(1));
            }
        }
        catch(SQLException e){
            System.err.println(e.getMessage());
            e.printStackTrace();
        }
        finally{
            try{
                if (rs != null) rs.close();
                if (cstmt != null) stmt.close();
                if (con != null) con.close();
            }
            catch(SQLException e){
                System.err.println(e.getMessage());
                e.printStackTrace();
            }
        }
    }
}
コンパイル & テスト
C:\src>javac MyProcedure.java
C:\src>javac TestClient.java

C:\src>java TestClient
  id::1
name::nurai
addFirstName::naoki nurai


へー。

DBによっては、ストアドからクラスが呼べるなんて初めて知りました。

まだまだ勉強不足。

参考にさせていただいたサイト

*1:Derby(JavaDB)をインストールしたディレクトリ

*2:指定したdbスキーマ[test_db]が無い場合、作成して接続