JDBC:Oracle存储过程返回嵌套表

时间:2016-01-12 16:39:18

标签: java oracle stored-procedures jdbc

我在oracle(12c)中有一个存储过程:

PROCEDURE work(a OUT VARCHAR2, b OUT SYS_REFCURSOR)

当我调用该过程时,游标的结果包含行,该行包含一些原始值+一个自定义类型:

CREATE TYPE ELEM AS OBJECT(ElemID INTEGER))
CREATE TYPE LIST AS TABLE OF ELEM

因此,结果如下:

vcursor:
------------------
COL1 COL2 LIST
------------------
A    B    LIST([ELEM],[ELEM])
C    D    LIST([ELEM],[ELEM],[ELEM])
E    F    LIST([ELEM])

有一个集合Oracle tutorial的教程(如果链接丢失,谷歌“使用Oracle集合”)。到目前为止,本教程对我没什么用。

这是我在java中所做的:

Connection conn = ...
CallableStatement statement = conn.prepareCall("{call work()}");
statement.registerOutParameter(1, OracleTypes.VARCHAR);
statement.registerOutParameter(2, OracleTypes.CURSOR);
statement.execute();

ResultSet rs = statement.getResultSet(2);
// here should be the code which retrieves the nested table elements
rs.next()
Array list = rs.getArray(3); //oracle.sql.ARRAY
Object[] elems = (Object[]) list.getArray(); // doesn't work
// I also tried list.getResultSet()

在调试中我确实看到如果我转换为oracle.sql.ARRAY并调用getOracleArray()然后我看到正确的大小和带有Struct []的Datum []数组,但是普通的sql方法什么也没给我。例如,来自数组的getResultSet返回一个ResultSet,其中next始终返回true,但没有元数据和实际数据。 getArray()返回numElements = -1等的数组。

我尝试使用typeMap而没有运气:

Map map = conn.getTypeMap();
map.put("ELEM", Elem.class); 
//map.put("SCHEMA.ELEM", Elem.class); 
//map.put("LIST", Elem.class); 
//map.put("SCHEMA.LIST", Elem.class); 
conn.setTypeMap(map);

请帮助和建议。提前谢谢。

1 个答案:

答案 0 :(得分:1)

我害怕我正在努力重现你所看到的行为。我试图整理一些可以重现你的问题的代码,但它确实有效。代码如下,我希望它对您有用。

我使用类型ELEM的类型映射条目,但不使用LIST类型。我也无法在CallableStatement接口上找到getResultSet(int)方法,因此我使用getObject(int)代替ResultSet将其转换为CREATE TYPE elem AS OBJECT(ElemID INTEGER); / CREATE TYPE list AS TABLE OF elem; / CREATE OR REPLACE PROCEDURE work(a OUT VARCHAR2, b OUT SYS_REFCURSOR) AS BEGIN a := 'test 1234'; OPEN b FOR SELECT 'A' AS col1, 'B' AS col2, list(elem(14), elem(17)) FROM DUAL UNION ALL SELECT 'C' AS col1, 'D' AS col2, list(elem(8), elem(4), elem(11)) FROM DUAL UNION ALL SELECT 'E' AS col1, 'F' AS col2, list(elem(-1)) FROM DUAL; END work; /

如果重要,我在Windows 10 x64上使用Oracle 11g XE 11.2.0.2.0,Java 1.8.0_60,ojdbc7.jar版本12.1.0.2.0。我也尝试了ojdbc6.jar和ojdbc5.jar的版本,它们也有相同的结果。

SQL:

import java.sql.*;

public class Elem implements SQLData {

    private Integer elementId;

    public String getSQLTypeName() { return "ELEM"; }

    public void readSQL(SQLInput input, String typeName) throws SQLException {
        elementId = input.readInt();
    }

    public void writeSQL(SQLOutput output) {
        throw new UnsupportedOperationException();
    }

    public String toString() {
        return "<Element " + elementId + ">";
    }
}

Elem.java:

import java.sql.*;
import java.util.*;

public class JDBCStructs {
    public static void main(String[] args) throws Exception {
        Connection c = ...

        Map<String, Class<?>> map = c.getTypeMap();
        map.put("ELEM", Elem.class);
        c.setTypeMap(map);        

        CallableStatement cs = c.prepareCall("{call work(?, ?)}");
        cs.registerOutParameter(1, Types.VARCHAR);
        cs.registerOutParameter(2, oracle.jdbc.OracleTypes.CURSOR);
        cs.execute();
        String a = cs.getString(1);
        System.out.println("Got string " + a);
        ResultSet rSet = (ResultSet)cs.getObject(2);
        while (rSet.next()) {
            String col1 = rSet.getString(1);
            String col2 = rSet.getString(2);
            Array list = (Array)rSet.getObject(3);
            System.out.println("Got " + col1 + ", " + col2 + " and " + Arrays.toString((Object[])list.getArray()));
        }
    }
}

JDBCStructs.java:

Got string test 1234
Got A, B and [<Element 14>, <Element 17>]
Got C, D and [<Element 8>, <Element 4>, <Element 11>]
Got E, F and [<Element -1>]

输出:

: