一个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] 用户名是:[张三]
您的 用户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
- 一个JDBC驱动的陷阱
- 一个不安分的JDBC驱动
- oracle连接驱动jdbc的一个bug
- 模型驱动开发的陷阱
- RecyclerView 的一个陷阱
- JDBC驱动的安装
- JDBC驱动的安装
- Singleton的JDBC驱动
- 关于jdbc的驱动
- JDBC的驱动类型
- DataDirect的JDBC驱动
- SQLServer2000的JDBC驱动
- jdbc的驱动jtds
- DB2的JDBC驱动
- DB2的JDBC驱动
- Java的一个小陷阱
- ListView的一个小陷阱!
- 操作Cookie的一个陷阱
- 1107 Social Clusters
- QT 对网址的解析和组合
- Android程序猿必看之《终端应用开发指南》
- 类模板“无法解析的外部符号”问题
- 蓝桥杯:找素数
- 一个JDBC驱动的陷阱
- spring + redis 实现数据的缓存
- Class.forName和ClassLoader.loadClass的区别
- iOS开发系列--触摸事件、手势识别、摇晃事件、耳机线控
- Android 实现通知栏显示多个notification
- @OneToMany三种设置方式详解
- Json数据整理(org-Json + json-lib)
- Linux初讲——安装图形界面
- BigDecimal