1. 概述
CallableStatement 用来运行 SQL 存储过程。存储过程是数据库中已经存在的 SQL 语句,
它通过名字调用。
CallableStatement 是 PreparedStatement 的子类。CallableStatement 中定义的方法用于处
理 OUT 参数或 INOUT 参数的输出部分:注册 OUT 参数的 JDBC 类型(一般 SQL 类型)、
从这些参数中检索结果,或者检查所返回的值是否为 JDBC NULL。
2. 创建 CallableStatement 对象
CallableStatement 对 象 是 用 Connection.prepareCall 创 建 的 。 以 下 代 码 创 建
CallableStatement 对象,其中含有对存储过程 p1 的调用,con 为连接对象:
CallableStatement cstmt = con.prepareCall("call p1(?, ?)");
其中"?"占位符为 IN、OUT 还是 INOUT 参数,取决于存储过程 p1。
3. IN 和 OUT 参数
将 IN 参数传给 CallableStatement 对象是通过 setXXX 方法完成的。该方法继承自
PreparedStatement。所传入参数的类型决定了所用的 setXXX 方法(例如,用 setString 来传
入 String 值等)。
如果存储过程返回 OUT 参数,则在执行 CallableStatement 对象之前必须先注册每个 OUT
参数的 JDBC 类型,有的参数还要同时提供刻度。注册 JDBC 类型是用 registerOutParameter
方法来完成的。语句执行完后,CallableStatement 的 getXXX 方法将取回参数值。其中 XXX
是为各参数所注册的 JDBC 类型所对应的 Java 类型。换言之, registerOutParameter 使用的
是 JDBC 类型(因此它与数据库返回的 JDBC 类型匹配),而 getXXX 将之转换为 Java 类型。
设存储过程 p1 的定义如下:
CREATE OR REPLACE PROCEDURE p1( a1 IN VARCHAR(10), a2 OUT VARCHAR(50)) AS DECLARE CURSOR CUR1 FOR SELECT name FROM person.person WHERE personid = a1; BEGIN OPEN CUR1; FETCH CUR1 INTO a2; END;
以下代码先注册 OUT 参数,执行由 cstmt 所调用的存储过程,然后检索通过 OUT 参数
返回的值。方法 getString 从 OUT 参数中取出字符串:
CallableStatement cstmt = con.prepareCall("call p1(?, ?)"); cstmt.setString(1, "1"); cstmt.registerOutParameter(2, java.sql.Types.VARCHAR); cstmt.executeUpdate(); String x = cstmt.getString(2);
4. INOUT 参数
如 果 参 数 为 既 接 受 输 入 又 接 受 输 出 的 参 数 类 型 ( INOUT 参 数 ), 那 么 除 了 调 用
registerOutParameter 方法外,还要调用对应的 setXXX 方法(继承自 PreparedStatement)。
setXXX 方法将参数值设置为输入参数,而 registerOutParameter 方法将它的 JDBC 类型注册
为输出参数。setXXX 方法提供一个 Java 值,驱动程序先把这个值转换为 JDBC 值,然后将
它送到数据库服务器。
该 IN 值的 JDBC 类型和提供给 registerOutParameter 方法的 JDBC 类型应该相同。如果
要检索输出值,就要用对应的 getXXX 方法。
设有一个存储过程 p2 的定义如下:
CREATE OR REPLACE PROCEDURE p2(a1 IN OUT VARCHAR(10)) AS DECLARE CURSOR CUR1 FOR SELECT name FROM person.person WHERE personid = a1; BEGIN OPEN CUR1; FETCH CUR1 INTO a1; END;
以下代码中,方法 setString 把参数设为“1”。然后,registerOutParameter 将该参数注册
为 JDBC VARCHAR。执行完该存储过程后,将返回一个新的 JDBC VARCHAR 值。方法
getString 将把这个新值作为 Java 的 String 类型返回。
CallableStatement cstmt = con.prepareCall("call p2(?)"); cstmt.setString(1, "1"); cstmt.registerOutParameter(1, java.sql.Types.VARCHAR); cstmt.executeUpdate(); String x = cstmt.getString(1);
5. 利用参数名进行操作
在通常的情况下一般采用参数索引来进行赋值。JDBC3.0 规范要求可以利用参数名来对
参数进行赋值,DM JDBC 驱动程序实现了这一点。如果某个存储过程的一些参数有默认值,
这时候采用参数名进行赋值就非常有用,用户可以只对那些没有默认值的参数进行赋值。参
数名可以通过调用 DatabaseMetaData.getProcedureColumns()来获得。
下面的代码中,存储过程 p2 为上面那个存储过程 p2。利用参数名进行操作:
CallableStatement cstmt = con.prepareCall("CALL p2 (?)"); cstmt.setString("a1", "1"); cstmt.registerOutParameter("a1", java.sql.Types.VARCHAR); cstmt.executeUpdate(); String x = cstmt.getString("a1");
而且,在读取参数的值和进行参数注册的时候,setXXX、getXXX、registerOutParameter
也都可以采用参数名来进行操作。通过调用 DatabaseMetaData.supportsNamedParameters()方
法就可以确定 JDBC 驱动程序是否支持利用参数名来进行操作。
注意:
在执行同一条语句的过程中,不允许交叉使用参数索引和参数名来进行操作,否则
会抛出异常。
6. 自定义方法列表
为了实现对达梦数据库所提供的时间间隔类型和带纳秒的时间类型的支持,在实现
CallableStatement 接 口 的 过 程 中 , 增 加 了 一 些 自 定 义 的 扩 展 方 法 。 用 户 将 获 得 的
CallableStatement 对象反溯成 DmdbCallableStatment 类型就可以访问这些方法。这些方法所
涉及到的扩展类请参看 4.4 DM JDBC 扩展这一节。
表 4.3 自定义方法列表
方法名 |
功能说明 |
getINTERVALYM(int) |
获得参数的值 |
getINTERVALYM(String) |
获得参数的值 |
getINTERVALDT(int) |
获得参数的值 |
getINTERVALDT(String) |
获得参数的值 |
getTIME(int) |
获得参数的值 |
getTIME(String) |
获得参数的值 |
setTIME(String,String) |
根据参数名来设置 DmdbTime 类型值。 |
setINTERVALDT(String,String) |
根据参数名来设置 DmdbIntervalDT 类型值。 |
setINTERVALYM(String,String) |
设置参数为年-月时间间隔类型值 |
另外,DM 中不支持 JDBC 规范中所要求的标准方法 setURL、getURL 和 getRef。由于
CallableStatement 是 PreparedStatement 的子类,因此,它将继承 PreparedStatement 的所有的
方法。
评论