一个JDBC驱动的陷阱

来源:互联网 发布:帝国cms图片集正则 编辑:程序博客网 时间:2024/05/11 00:20

近期公司的项目在升级Oracle 12C,除了要替换wm_concat之类的不能用的函数之类的预料中的问题外,我还遇到了一个挺奇怪的JDBC驱动问题:


就是使用JDBC调用存储过程时,发现获取的CallableStatement接口对象的setObject方法,用“命名参数”时有问题。


为了描述方便,我写成了一个小DEMO。


首先,有一个存储过程

CREATE OR REPLACE PROCEDURE PRINT_USER(       USERID        IN  VARCHAR2,       USERNAME      IN  VARCHAR2,       PRINTINFO     OUT VARCHAR2)ASBEGIN      PRINTINFO := '您的   用户ID是:['||USERID||']    用户名是:['||USERNAME||']';EXCEPTION  WHEN OTHERS THEN    PRINTINFO := SQLCODE||'-'||SQLERRM;END;


然后,编写一个简单的Java程序来调用一下它,并打印出它的出参。

package com.dullchap.db.driverproblem;import java.sql.CallableStatement;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;public class TestDao {static Connection  conn;static ResultSet  rs;static PreparedStatement stmt;public static void main(String[] args) throws Exception{try {//加载驱动,获取链接Class.forName("oracle.jdbc.driver.OracleDriver");conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl1", "scott", "scott");//获取存储过程执行对象CallableStatement lcs_state = conn.prepareCall("BEGIN PRINT_USER(:USERID,:USERNAME,:PRINTINFO); END;");//设置存储过程出/入参数lcs_state.setObject("USERNAME", "张三");lcs_state.setObject("USERID", "123");lcs_state.registerOutParameter("PRINTINFO", java.sql.Types.VARCHAR);//执行存储过程lcs_state.executeUpdate();//打印存储过程结果System.out.println(lcs_state.getObject("PRINTINFO"));} catch (Exception e) {e.printStackTrace();} finally {//释放连接if (rs != null)rs.close();if (stmt != null)stmt.close();if (conn != null)conn.close();}}}

未升级Oracle 12C前,执行结果当然是没问题的,如下:

您的   用户ID是:[123]    用户名是:[张三]



但升级了Oracle 12C,并使用新的jdbc驱动包(ojdbc7.jar)时,问题来了,发现打印结果如下:

您的   用户ID是:[张三]    用户名是:[123]


经调查之后,发现ojdbc7.jar完全忽略了CallableStatement对应对象的setObject方法的第一个参数,


它完全按照先后顺序来给存储过程入参赋值了。


也就是说,我如果把代码的setObject那两行交换一下顺序,程序的输出也是正常的。


我在Oracle官网也查看了一下,有提到setObject(String,Object)是不推荐使用的方法了。还是老老实实用回setObject(int,Ojbect),乖乖写问号吧。

package com.dullchap.db.driverproblem;import java.sql.CallableStatement;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;public class TestDao {static Connection  conn;static ResultSet  rs;static PreparedStatement stmt;public static void main(String[] args) throws Exception{try {//加载驱动,获取链接Class.forName("oracle.jdbc.driver.OracleDriver");conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl1", "scott", "scott");//获取存储过程执行对象//CallableStatement lcs_state = conn.prepareCall("BEGIN PRINT_USER(:USERID,:USERNAME,:PRINTINFO); END;");CallableStatement lcs_state = conn.prepareCall("BEGIN PRINT_USER(?,?,?); END;");//设置存储过程出/入参数//lcs_state.setObject("USERNAME", "张三");//lcs_state.setObject("USERID", "123");//lcs_state.registerOutParameter("PRINTINFO", java.sql.Types.VARCHAR);lcs_state.setObject(2, "张三");lcs_state.setObject(1, "123");lcs_state.registerOutParameter(3, java.sql.Types.VARCHAR);//执行存储过程lcs_state.executeUpdate();//打印存储过程结果//System.out.println(lcs_state.getObject("PRINTINFO"));System.out.println(lcs_state.getObject(3));} catch (Exception e) {e.printStackTrace();} finally {//释放连接if (rs != null)rs.close();if (stmt != null)stmt.close();if (conn != null)conn.close();}}}



0 0
原创粉丝点击