我的问题与this post和a post of mine有关。我试图在使用JDBC调用PL / SQL过程时将REF_CURSOR作为IN参数传递。这是我的代码:
public int printMaxSalAllDept()
{
Connection conn = null;
OracleCallableStatement callStmt = null;
int rowCount = -1;
try
{
// Register the Jdbc Driver
// Class.forName(JDBC_DRIVER_ORACLE);
// Create a Database connection
conn = DriverManager.getConnection(DB_URL,DB_USER,DB_PWD);
// Create a query string to get the ResultSet of your choice
String getRsQuery = "SELECT e.department_id , e.last_name , "
+ "e.salary FROM employees e , (SELECT department_id , "
+ "MAX(salary) AS maxSal FROM employees GROUP BY department_id) "
+ "m WHERE e.department_id = m.department_id "
+ "AND e.salary = m.maxSal ORDER BY e.salary";
// Create a Statement
Statement stmt = conn.createStatement();
// Execute the statement
ResultSet rs = stmt.executeQuery(getRsQuery);
// Create a SQL String
String callProc = "{ call HR.EMP_PKG.print_max_sal_all_dept(? , ?) }";
// Create a Callable Statement
callStmt = (OracleCallableStatement) conn.prepareCall(callProc);
// Bind values to the IN parameter
callStmt.setCursor(1, rs);
// callStmt.setNull(1,OracleTypes.CURSOR);
// Register OUT parameters type to the SQL type of the value returned
callStmt.registerOutParameter(2, java.sql.Types.NUMERIC);
// Execute Callable Statements
callStmt.execute();
// Retrieve value from the OUT parameters
rowCount = callStmt.getInt(0);
System.out.println("Number of rows in the cursor :" + rowCount);
}
catch (SQLException se)
{
System.out.println("Exception occured in the database");
System.out.println("Exception message: "+ se.getMessage());
System.out.println("Database error code: "+ se.getErrorCode());
se.printStackTrace();
}
finally
{
// Clean up
if(callStmt != null)
{
try
{
callStmt.close();
}
catch (SQLException se2)
{
se2.printStackTrace();
}
}
if(conn != null)
{
try
{
conn.close();
}
catch (SQLException se2)
{
se2.printStackTrace();
}
}
}
return rowCount;
}
当我运行上面的代码时,我得到以下异常:
Exception occured in the database
java.sql.SQLException: Unsupported feature
at oracle.jdbc.driver.OraclePreparedStatement.setCursorInternal(OraclePreparedStatement.java:5867)
at oracle.jdbc.driver.OracleCallableStatement.setCursor(OracleCallableStatement.java:5297)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.setCursor(OraclePreparedStatementWrapper.java:410)
at com.rolta.HrManager.printMaxSalAllDept(HrManager.java:1038)
at com.rolta.HrManager.main(HrManager.java:1344)
Exception message: Unsupported feature
Database error code: 17023
我在这个论坛上看过几篇帖子,其他人建议更新到最新版本的JDBC驱动程序修复了这个问题。就我而言,我使用最新版本的Oracle JDBC驱动程序(ojdbc6.jar
Oracle Database 11g Release 2 11.2.0.4 JDBC Drivers下的第一个jar)。所以我不认为它是导致问题的版本。
如果我所做的是非法的,抛出的异常消息就表明了这一点。 但是在“不支持的功能”消息中,似乎此功能对我的数据库(或我正在使用的版本(11g))或我正在使用的JDBC驱动程序版本不可用。这是对此例外的正确解释吗?
答案 0 :(得分:1)
我想说在任何版本的JDBC驱动程序中都不支持该功能,并且永远不会支持该功能。在这种情况下,数据库的版本无关紧要。
我不能说为什么在setCursor()
中声明了OraclePreparedStatement
方法。我猜这是API设计中的一个错误。实际上,如果编译试图调用setCursor()
的任何代码:
C:\>javac -Xlint JavaRefCursorTest.java
JavaRefCursorTest.java:28: warning: [deprecation] setCursor(int,ResultSet) in OraclePreparedStatement has been deprecated
((OracleCallableStatement)cstmt2).setCursor(1, rSet);
^
1 warning
此弃用警告表明Oracle计划在将来删除此方法。
我还使用Oracle 12c JDBC驱动程序(ojdbc7.jar)从my answer to one of your previous questions运行我的JavaRefCursorTest
类。最终结果只是略有不同:调用setCursor()
时抛出的异常类型是java.sql.SQLFeatureNotSupportedException
而不是java.sql.SQLException
。因此升级JDBC驱动程序JAR无济于事。
在你的情况下,我看不出你为什么想要从数据库和JDBC ResultSet
中获取引用游标的原因,只能将相同的ResultSet
直接传递给数据库。您可以使用PL / SQL块直接使用引用游标调用该过程,如下所示:
String plsql =
"DECLARE" +
" l_curs SYS_REFCURSOR; " +
"BEGIN" +
" OPEN l_curs FOR" +
" SELECT e.department_id , e.last_name ," +
" e.salary FROM employees e , (SELECT department_id ," +
" MAX(salary) AS maxSal FROM employees GROUP BY department_id)" +
" m WHERE e.department_id = m.department_id" +
" AND e.salary = m.maxSal ORDER BY e.salary;" +
"" +
" HR.EMP_PKG.print_max_sal_all_dept(l_curs, ?);" +
"END;"
PreparedStatement stmt = conn.prepareStatement(plsql);
stmt.registerOutParameter(1, java.sql.Types.NUMERIC);
stmt.execute();