【发布时间】:2016-08-24 07:10:57
【问题描述】:
我必须在 Oracle (11g) 中调用一个使用单个 IN OUT 参数的存储过程。该参数是定义为
的 Oracle 自定义类型 CREATE OR REPLACE TYPE "SEPADD"."T_NAPRAVI_NALOG_TEST" IS OBJECT
(
I_INICIJALI varchar2(3) ,
I_STATUS number(1)
)
实际类型更复杂,但我在这里对其进行了简化以提高可读性。使用这种类型(再次简化)的 Oracle 过程定义为
CREATE OR REPLACE PROCEDURE "SEPADD"."GETNALOGTESTPROC"(nalog in out T_NAPRAVI_NALOG_TEST )
IS
BEGIN
nalog.I_INICIJALI := 'PC';
nalog.I_STATUS := nalog.I_STATUS + 3;
END;
Oracle 自定义类型映射到实现 SQLData 接口的 Java 类。 (见https://docs.oracle.com/javase/tutorial/jdbc/basics/sqlcustommapping.html#implementing_sqldata)
public class TNapraviNalog implements SQLData{
private int I_STATUS;
private String I_INICIJALI;
private String sql_type = "T_NAPRAVI_NALOG_TEST";
public String getSQLTypeName() {
return sql_type;
}
public int getIStatus(){
return this.I_STATUS;
}
public String getIInicijali(){
return this.I_INICIJALI;
}
public void setIInicijali(String in){
I_INICIJALI = in;
}
public void setIStatus(int st){
I_STATUS = st;
}
public void readSQL(SQLInput stream, String type)
throws SQLException {
sql_type = type;
I_INICIJALI = stream.readString();
I_STATUS = stream.readInt();
}
public void writeSQL(SQLOutput stream)
throws SQLException {
stream.writeString(I_INICIJALI);
stream.writeInt(I_STATUS);
}
}
现在,从我的 JDBC 代码中,我按以下方式调用 Oracle 存储过程
Object obj=null;
ResultSet rs=null;
CallableStatement stmt=null;
TNapraviNalog n = null;
try{
sqlQuery = "{call getnalogtestproc(?)}";
Map m = conn.getTypeMap();
m.put("sepadd.T_NAPRAVI_NALOG_TEST", Class.forName("ib.easyorm.db.TNapraviNalog"));//this maps the Java class to the Oracle custom type
conn.setTypeMap(m);
stmt=conn.prepareCall(sqlQuery);
stmt.registerOutParameter(1, Types.STRUCT, "T_NAPRAVI_NALOG_TEST");
stmt.setObject(1, paramValues.get(0) ); //paramValues.get(0) returns an instance of TNapraviNalog class
stmt.execute();
obj = stmt.getObject(1, m);
//obj = stmt.getObject(1,TNapraviNalog.class); this method is not implemented in the JDBC driver
}catch(Exception e){
throw new EasyORMException(e);
}finally{
closeResources(rs,stmt);
}
return obj;
现在,问题是,虽然我可以得到存储过程返回的结果,但结果并没有转换为 Java 类 (TNapraviNalog),所以我必须手动完成。我可以成功 使用 TNapraviNalog ( stmt.setObject(1, paramValues.get(0) ); ) 的实例调用 Oracle 过程,但我无法将结果转换为 TNapraviNalog。我真的很想 能够拥有类似的东西
TNapraviNalog nalog = stmt.getObject(1, m);
但是,这一行会导致异常(java.lang.ClassCastException: oracle.sql.STRUCT cannot be cast to ib.easyorm.db.TNapraviNalog)。 我猜测 JDBC 驱动程序不知道 stmt.getObject(1,m) 返回的实际类型,因此无法进行转换。
有人知道这是否可以使用普通的 JDBC 或 Hibernate 来完成?
编辑:Oracle 页面中的相关代码(cihan 七的答案中给出的链接)
从 Callable Statement OUT 参数中检索 SQLData 对象
假设您有一个调用 PL/SQL 函数 GETEMPLOYEE 的 OracleCallableStatement 实例 ocs。程序将员工编号传递给函数。该函数返回相应的 Employee 对象。要检索此对象,请执行以下操作:
1.准备一个OracleCallableStatement来调用GETEMPLOYEE函数,如下:
OracleCallableStatement ocs = (OracleCallableStatement)conn.prepareCall("{ ? = call GETEMPLOYEE(?) }");
2.将empnumber 声明为GETEMPLOYEE 的输入参数。使用类型代码 OracleTypes.STRUCT 将 SQLData 对象注册为 OUT 参数。然后,运行语句。这可以按如下方式完成:
ocs.setInt(2, empnumber);
ocs.registerOutParameter(1, OracleTypes.STRUCT, "EMP_OBJECT");
ocs.execute();
3.使用getObject 方法检索员工对象。以下代码假设有一个类型映射条目将 Oracle 对象映射到 Java 类型 Employee:
Employee emp = (Employee)ocs.getObject(1); //my comment-->this doesn't seem to work
如果没有类型映射条目,则 getObject 将返回一个 oracle.sql.STRUCT 对象。将输出转换为 STRUCT 类型,因为 getObject 方法返回通用 java.lang.Object 类的实例。这样做如下:
STRUCT emp = (STRUCT)ocs.getObject(1);
谢谢
【问题讨论】:
标签: java oracle stored-procedures jdbc