oracle - 使用 JDBC 从存储过程中获取 Oracle 表类型

标签 oracle stored-procedures jdbc resultset out-parameters

我试图了解使用 JDBC 从 Oracle 存储过程/函数获取表数据的不同方法。六种方式如下:

  • 过程返回模式级表类型作为 OUT 参数
  • 过程返回包级表类型作为 OUT 参数
  • 过程返回包级游标类型作为 OUT 参数
  • 返回模式级表类型的函数
  • 返回包级表类型的函数
  • 返回包级游标类型的函数

  • 以下是 PL/SQL 中的一些示例:

    -- schema-level table type
    CREATE TYPE t_type AS OBJECT (val VARCHAR(4));
    CREATE TYPE t_table AS TABLE OF t_type;
    
    CREATE OR REPLACE PACKAGE t_package AS
      -- package level table type
      TYPE t_table IS TABLE OF some_table%rowtype;
      -- package level cursor type
      TYPE t_cursor IS REF CURSOR;
    END library_types;
    
    -- and example procedures:
    CREATE PROCEDURE p_1 (result OUT t_table);
    CREATE PROCEDURE p_2 (result OUT t_package.t_table);
    CREATE PROCEDURE p_3 (result OUT t_package.t_cursor);
    CREATE FUNCTION f_4 RETURN t_table;
    CREATE FUNCTION f_5 RETURN t_package.t_table;
    CREATE FUNCTION f_6 RETURN t_package.t_cursor;
    

    我已经成功地用 JDBC 调用了 3、4 和 6:

    // Not OK: p_1 and p_2
    CallableStatement call = connection.prepareCall("{ call p_1(?) }");
    call.registerOutParameter(1, OracleTypes.CURSOR);
    call.execute(); // Raises PLS-00306. Obviously CURSOR is the wrong type
    
    // OK: p_3
    CallableStatement call = connection.prepareCall("{ call p_3(?) }");
    call.registerOutParameter(1, OracleTypes.CURSOR);
    call.execute();
    ResultSet rs = (ResultSet) call.getObject(1); // Cursor results
    
    // OK: f_4
    PreparedStatement stmt = connection.prepareStatement("select * from table(f_4)");
    ResultSet rs = stmt.executeQuery();
    
    // Not OK: f_5
    PreparedStatement stmt = connection.prepareStatement("select * from table(f_5)");
    stmt.executeQuery(); // Raises ORA-00902: Invalid data type
    
    // OK: f_6
    CallableStatement call = connection.prepareCall("{ ? = call f_6 }");
    call.registerOutParameter(1, OracleTypes.CURSOR);
    call.execute();
    ResultSet rs = (ResultSet) call.getObject(1); // Cursor results
    

    很明显,我很难理解
  • 如何从存储过程中的 OUT 参数中检索模式级和包级表类型
  • 如何从存储函数中检索包级表类型

  • 我似乎找不到任何关于此的文档,因为每个人总是使用游标而不是表类型。也许是因为不可能?不过,我更喜欢表类型,因为它们是正式定义的,并且可以使用字典 View (至少是模式级别的表类型)来发现。

    注意:显然,我可以编写一个返回 OUT 参数和包级表类型的包装函数。但我更喜欢干净的解决方案。

    最佳答案

    您不能从 java 访问 PLSQL 对象(情况 2 和 5 = 包级对象),请参阅 "java - passing array in oracle stored procedure" .但是,您可以访问 SQL 类型(案例 1 和 4)。

    从PL/SQL获取OUT参数到java,可以使用one of Tom Kyte's thread中描述的方法使用 OracleCallableStatement。您的代码将有一个额外的步骤,因为您正在检索 Object 表而不是 VARCHAR 表。

    这是一个使用 SQL 对象表的演示,首先是设置:

    SQL> CREATE TYPE t_type AS OBJECT (val VARCHAR(4));
      2  /
    Type created
    
    SQL> CREATE TYPE t_table AS TABLE OF t_type;
      2  /
    Type created
    
    SQL> CREATE OR REPLACE PROCEDURE p_sql_type (p_out OUT t_table) IS
      2  BEGIN
      3     p_out := t_table(t_type('a'), t_type('b'));
      4  END;
      5  /
    Procedure created
    

    实际的 java 类(使用 dbms_output.put_line 来记录,因为我将从 SQL 调用它,如果从 java 调用使用 System.out.println):
    SQL> CREATE OR REPLACE
      2  AND COMPILE JAVA SOURCE NAMED "ArrayDemo"
      3  as
      4  import java.sql.*;
      5  import oracle.sql.*;
      6  import oracle.jdbc.driver.*;
      7  
      8  public class ArrayDemo {
      9     
     10     private static void log(String s) throws SQLException {
     11        PreparedStatement ps =
     12           new OracleDriver().defaultConnection().prepareStatement
     13           ( "begin dbms_output.put_line(:x); end;" );
     14        ps.setString(1, s);
     15        ps.execute();
     16        ps.close();
     17     }
     18  
     19     public static void getArray() throws SQLException {
     20  
     21        Connection conn = new OracleDriver().defaultConnection();
     22  
     23        OracleCallableStatement cs =
     24           (OracleCallableStatement)conn.prepareCall
     25           ( "begin p_sql_type(?); end;" );
     26        cs.registerOutParameter(1, OracleTypes.ARRAY, "T_TABLE");
     27        cs.execute();
     28        ARRAY array_to_pass = cs.getARRAY(1);
     29  
     30        /*showing content*/
     31        Datum[] elements = array_to_pass.getOracleArray();
     32  
     33        for (int i=0;i<elements.length;i++){
     34           Object[] element = ((STRUCT) elements[i]).getAttributes();
     35           String value = (String)element[0];
     36           log("array(" + i + ").val=" + value);
     37        }
     38     }
     39  }
     40  /
    Java created
    

    让我们称之为:
    SQL> CREATE OR REPLACE
      2  PROCEDURE show_java_calling_plsql
      3  AS LANGUAGE JAVA
      4  NAME 'ArrayDemo.getArray()';
      5  /
    
    Procedure created
    
    SQL> EXEC show_java_calling_plsql;
    
    array(0).val=a
    array(1).val=b
    

    关于oracle - 使用 JDBC 从存储过程中获取 Oracle 表类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6410452/

    相关文章:

    oracle - 如何删除 oracle 数据库快捷版

    oracle - 来自 dbms_metadata.get_ddl 的自定义表 DDL

    javascript - Ajax 调用一直给我 "internal server error 500"

    php - 在 PHP 中调用带有 OUT 参数的存储过程

    java - MYSQL特殊字符问题

    java - Oracle 如何在从 plsql 调用 java 时导入缺少的 java 类

    oracle - 不带参数调用 Oracle 存储过程

    PHP:使用 INPUT 和 OUTPUT 参数调用 MySQL 存储过程(NOT "INOUT")

    mysql - sonar-runner 延迟三分钟 "Store results in database"(jdbc/mysql)

    JAVA Sqlite 西里尔字母显示为?