使用JDBC从存储过程中获取Oracle表types
我想了解使用JDBC从Oracle存储过程/函数获取表数据的不同方法。 六种方式是以下几种:
- 过程返回模式级别的表types作为OUT参数
- 过程返回一个包级表types作为OUT参数
- 过程返回一个包级光标types作为OUT参数
- 函数返回一个模式级别的表types
- 函数返回一个包级表types
- 函数返回一个包级光标types
这里是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参数中检索模式级和包级表types
- 如何从存储函数中检索包级表types
我似乎无法find任何文档,因为每个人都使用游标,而不是表types。 也许因为这是不可能的? 不过,我更喜欢表types,因为它们是正式定义的,可以使用字典视图(至less是模式级表types)来发现。
注意:显然,我可以编写一个返回OUT参数和包级表types的包装函数。 但我更喜欢干净的解决scheme。
您不能从java访问PLSQL对象(情况2&5 =包级对象),请参阅“java – 在oracle存储过程中传递数组” 。 但是,您可以访问SQLtypes(情况1和4)。
为了从PL / SQL中获得OUT参数到java,你可以使用Tom Kyte的线程中使用OracleCallableStatement描述的方法。 您的代码将有一个额外的步骤,因为您正在检索一个对象的表,而不是一个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
logging,因为我将从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
你也可以使用下面的一个
public List<EmployeeBean> fetchDataFromSPForRM(String sInputDate) { List<EmployeeBean> employeeList = new ArrayList<EmployeeBean>(); Connection dbCon = null; ResultSet data = null; CallableStatement cstmt = null; try { dbCon = DBUtil.getDBConnection(); String sqlQuery = "{? = call PKG_HOLD_RELEASE.FN_RM_PDD_LIST()}"; cstmt = dbCon.prepareCall(sqlQuery); cstmt.registerOutParameter(1, OracleTypes.CURSOR); cstmt.execute(); data = (ResultSet) cstmt.getObject(1); while(data.next()){ EmployeeBean employee = new EmployeeBean(); employee.setEmpID(data.getString(1)); employee.setSubBusinessUnitId((Integer)data.getObject(2)); employee.setMonthOfIncentive((Integer)data.getObject(3)); employee.setPIPStatus(data.getString(5)); employee.setInvestigationStatus(data.getString(6)); employee.setEmpStatus(data.getString(7)); employee.setPortfolioPercentage((Integer)data.getObject(8)); employee.setIncentive((Double)data.getObject(9)); employee.setTotalSysemHoldAmt((Double)data.getObject(10)); employee.setTotalManualHoldAmt((Double)data.getObject(11)); employeeList.add(employee); } } catch (SQLException e) { e.printStackTrace(); }finally{ try { if(data != null){ data.close(); data = null; } if(cstmt != null){ cstmt.close(); cstmt = null; } if(dbCon != null){ dbCon.close(); dbCon = null; } } catch (SQLException e) { e.printStackTrace(); } } return employeeList; }