una procedimientos procedimiento llamar funciones funcion ejemplos ejemplo ejecutar developer desde callablestatement almacenados almacenado java jdbc parameters plsql cursor

java - procedimientos - Llamando al procedimiento PL/SQL con SYS_REFCURSOR como parámetro IN usando JDBC



procedimientos y funciones oracle pl sql (1)

Estoy tratando de entender cómo puedo llamar a un procedimiento PL / SQL que toma un parámetro SYS_REFCURSOR como IN .

Considere el siguiente procedimiento PL / SQL:

print_cursor_contents(myCursor SYS_REFCURSOR , row_count OUT NUMBER);

En el momento del valor de enlace al parámetro IN, ¿qué método setXXX debo usar?

Para mí, una clase Java con campos de registro de cursor individuales, como miembros y una matriz de instancias de esta clase, parece la forma correcta de representar un CURSOR plsql. Obtengo una SQLException cuando hago esto:

Usé el siguiente método de configuración

callStmt.setObject(1, curRec);

Aquí está la excepción que recibí por usar la declaración anterior:

Exception occured in the database Exception message: Invalid column type java.sql.SQLException: Invalid column type at oracle.jdbc.driver.OraclePreparedStatement.setObjectCritical(OraclePreparedStatement.java:8921) at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:8396) at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:9176) at oracle.jdbc.driver.OracleCallableStatement.setObject(OracleCallableStatement.java:5024) at oracle.jdbc.driver.OraclePreparedStatementWrapper.setObject(OraclePreparedStatementWrapper.java:234) at com.rolta.HrManager.printMaxSalAllDept(HrManager.java:1022) at com.rolta.HrManager.main(HrManager.java:1116) Database error code: 17004


Para mí, una clase Java con campos de registro de cursor individuales, como miembros y una matriz de instancias de esta clase, parece la forma correcta de representar un CURSOR plsql.

Estoy en desacuerdo.

Si tiene una función o procedimiento almacenado que devuelve un cursor ref o tiene un cursor ref como parámetro OUT , el cursor ref sale de JDBC como ResultSet . Entonces, si fuera posible llamar a un procedimiento almacenado con un parámetro SYS_REFCURSOR , sospecharía que un ResultSet sería lo que necesitaría pasar.

De hecho, mis sospechas están confirmadas. Si echa un vistazo a la extensión de Oracle a CallableStatement , OracleCallableStatement , hereda un setCursor(int, ResultSet) de su superinterfaz OraclePreparedStatement . Por lo tanto, podría convertir el CallableStatement a OracleCallableStatement , llamar al método setCursor y listo.

Excepto que este enfoque en realidad no funciona.

Si intentas llamar a setCursor en OracleCallableStatement , obtendrás una excepción java.sql.SQLException: Unsupported feature .

Puede intentar llamar a setObject con un ResultSet , pero solo obtendrá otra java.sql.SQLException: Invalid column type excepción de java.sql.SQLException: Invalid column type setObject .

Aquí hay una clase de prueba que puede ejecutar para verificar cualquier caso. Llama a un procedimiento almacenado para obtener un cursor de referencia (y por lo tanto un ResultSet ) y luego intenta pasarlo al otro:

import java.sql.*; import oracle.jdbc.OracleTypes; import oracle.jdbc.OracleCallableStatement; public class JavaRefCursorTest { public static void main(String[] args) throws Exception { Connection conn = DriverManager.getConnection( "jdbc:oracle:thin:@localhost:1521:XE", "user", "password"); try (CallableStatement cstmt1 = conn.prepareCall( "{ call java_ref_curs_test.get_ref_cursor(?)}")) { cstmt1.registerOutParameter(1, OracleTypes.CURSOR); cstmt1.execute(); try (ResultSet rSet = (ResultSet)cstmt1.getObject(1)) { try (CallableStatement cstmt2 = conn.prepareCall( "{ call java_ref_curs_test.print_refcursor(?)}")) { // Uncomment the next line to call setCursor: // ((OracleCallableStatement)cstmt2).setCursor(1, rSet); // Uncomment the next line to call setObject: // cstmt2.setObject(1, rSet); cstmt2.execute(); } } } } }

(Los dos procedimientos en java_ref_curs_test toman un solo parámetro SYS_REFCURSOR : get_ref_cursor devuelve un cursor de referencia e print_refcursor toma uno como parámetro pero no hace nada con él).

Entonces, ¿qué método setXXX deberías usar? Yo diría que ninguno de ellos. Lo que estás pidiendo no es posible directamente.

Todavía es posible llamar a este procedimiento, pero deberá crear el cursor de ref en PL / SQL, no en Java, y luego pasarlo a su procedimiento.

Por ejemplo, podría usar el siguiente bloque PL / SQL para llamar a los dos procedimientos utilizados en el ejemplo anterior:

DECLARE l_curs SYS_REFCURSOR; BEGIN java_ref_curs_test.get_ref_cursor(l_curs); java_ref_curs_test.print_refcursor(l_curs); END;

Puede ejecutar esto fácilmente desde JDBC: póngalo en una cadena y páselo a Statement.executeUpdate() .