いやー、悩みました。
ようやく解決。
Oracle DB で TYPE AS OBJECT とかを使用したテーブル、ストアドなどを、Spring Framework から利用するための情報です。
ここでは引数(INパラメータ)にTYPEがあるストアドを実行する場合で説明します。
Spring の StoredProcedure を利用します。
まず、実行だけだとこんな感じで実装します。
ストアドの引数が TYPE AS OBJECT の場合
StoredProcedure sp = new StoredProcedure(dataSource, "SCHEMA.STORED_NAME");
sp.declareParameter(new SqlParameter("PARAM_NAME", Types.STRUCT, "ORACLE_TYPE_NAME"));
Map param = new HashMap();
param.put("PARAM_NAME", new OracleStructTypeValue("ORACLE_TYPE_NAME", "aaa", "bbb"));
sp.execute(param);
1行目
Spring の
StoredProcedure
クラスのインスタンス化コンストラクタの引数は1つ目に
DataSource
、2つ目は実行するストアド名2行目
ストアドの引数の定義
今回はINパラメータ1つでそれがTYPEだった場合。TYPE は AS OBJECT 、つまり構造体的な場合。
StoredProcedure
クラスのdeclareParameter
メソッドに SqlParameter を渡す。SqlParameter
のコンストラクタの引数は以下のように指定する1つ目:引数名(任意の文字列)
2つ目:
java.sql.Types.STRUCT
を指定3つ目:Oracle 側の
TYPE
の名前3行目
実行時の引数となる
Map
の作成。4行目
ここがポイントかな。実行時引数のキーは2行目で指定した
SqlParameter
の1番目の引数のモノと同じにして、ポイントは値側。通常数値や文字列を渡すところを
org.springframework.jdbc.core.support.AbstractSqlTypeValue
を実装したクラスで指定する。今回は
OracleStructTypeValue
というクラスを作成。内容は以下のような形。
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import oracle.sql.STRUCT;
import oracle.sql.StructDescriptor;
import org.apache.commons.lang.StringUtils;
import org.springframework.jdbc.core.support.AbstractSqlTypeValue;
public class OracleStructTypeValue extends AbstractSqlTypeValue {
private String structName;
private Object[] parameterValues;
public OracleStructTypeValue(Object... args) {
parameterValues = args;
}
public OracleStructTypeValue(List args) {
parameterValues = args.toArray();
}
public OracleStructTypeValue(String structName, Object... args) {
this.structName = structName;
parameterValues = args;
}
public OracleStructTypeValue(String structName, List args) {
this.structName = structName;
parameterValues = args.toArray();
}
public void setStructName(String structName) {
this.structName = structName;
}
public void setParameterValue(Object[] parameterValues) {
this.parameterValues = parameterValues;
}
@Override
protected Object createTypeValue(Connection con, int sqlType, String typeName) throws SQLException {
StructDescriptor structDescriptor = StructDescriptor.createDescriptor(
StringUtils.isEmpty(structName) ? typeName : structName, con);
return new STRUCT(structDescriptor, con, parameterValues);
}
XMLからも定義できるように
setter
なども用意しましたが、基本はcreateTypeValue
というメソッドを実装すればOK。createTypeValue
の引数の3つ目typeName は、実行時に指定したTYPE名(最初のソースで言う2行目の SqlParameter
のコンストラクタ引数の3番目)が渡ってきます。基本はそれをそのままStructDescriptor
のcreateDescriptor
の1番目の引きすに渡せばOKだと思いますが、ここでは別途指定もできるようにしています。
createDescriptor
の2番目の引数は実行時にストアドに渡す具体的な値の配列。
Oracle側で定義したTYPEの上から順番に配列にして渡します。(最初のソースでは"aaa"と"bbb"という文字列を渡ています)
これで実行できます。
ただし注意点が。このcreateTypeValue
メソッドの引数となっているConnection
は OracleConnection
型でないとClassCastException
が出ます。
なので、DataSource
の設定を以下のようにしてあげる必要があります。
<bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource" method="close">
<property name="URL" value="jdbc:oracle:thin:@localhost:1521:orcl" />
<property name="user" value="scott" />
<property name="password" value="tiger" />
</bean>
今回はここまで。
TYPE の型が TABLE の場合とか、OUT パラメータの場合は次回以降で。(あるのか?)