はじめに
- 固定の数ではないパラメータをプロシージャに渡そうとして試行錯誤しました。
- 実装方法等を纏めます。
- ストアドプロシージャで確認していますが、ストアドファンクションでも同じだと思います。
環境
- 環境は以下です。おそらくこんな環境では開発しないと思いますが参考程度に。本質は変わらないとは思います。(jdkのバージョンが違っても本質は同じではないかと思います)
項目 | バージョン |
---|---|
JDK | 1.5 |
Oracle | 11 |
やりたいこと
- Oracleインスタンスに定義された、ストアドプロシージャをjavaから呼ぶ。
- ストアドプロシージャに渡すパラメータとして、数値の配列を渡したい。
実装
各種定義
- テスト用の簡単なテーブルを用意します。定義は以下です。
create table ARRAY_TEST (
id number,
name varchar2(256)
);
- TYPE_TABLE_OF_NUMBERという型を作成します。定義は以下です。
create or replace TYPE "TYPE_TABLE_OF_NUMBER" AS TABLE OF NUMBER
実装
プロシージャ
- プロシージャは以下のとおり。
- 変数名などはいい加減です。
create or replace procedure arrayTest(idsin TYPE_TABLE_OF_NUMBER)
as
begin
FOR i IN ids.first..ids.last LOOP
insert into ARRAY_TEST (id,name) values (ids(i),'dummy');
END LOOP;
commit;
end;
java側
- java側のコードは以下。
- パッケージ宣言やimportなどは省略しています。
- 接続情報は伏せてあります。
private static void executeStoredProcedure() throws SQLException {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
}
final String URL = "jdbc:oracle:thin:@xx.xx.xx.xx:port:sid";
final String USER = "user";
final String PASS = "pass";
String procedureSQL = "{call arrayTest(?)}";
Connection conn = DriverManager.getConnection(URL,USER,PASS);
try {
CallableStatement cs = conn.prepareCall(procedureSQL);
ArrayList ids = new ArrayList<Integer>();
ids.add(1);
ids.add(2);
ids.add(3);
ids.add(4);
ArrayDescriptor arrayDescriptor= ArrayDescriptor.createDescriptor(
"TYPE_TABLE_OF_NUMBER", conn);
ARRAY arrayParameter = new ARRAY(arrayDescriptor, conn, ids.toArray());
cs.setArray(1, arrayParameter);
cs.execute();
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("処理が完了しました");
}
}
補足
- 古いjdkだと、Class.forName("oracle.jdbc.driver.OracleDriver")を呼ばないと接続できないようです。
- createDescriptorであらかじめ定義された型の名称を渡しています。ここがパッケージ内に定義された型の場合はこの方法では動かないようです。
- <スキーマ名>.<パッケージ名>.<型名>という指定をしても見つからないというエラーになる。
- 以下のサイトに解決方法があるようなのですが、このやり方はたしかによくないと思います。(試していない)