从MySQL服务器5.0版开始,与Connector/J 3.1.1或更新版本一起使用时,可完全实现java.sql.CallableStatement接口,但getParameterMetaData()方法例外。
在MySQL参考手册的“存储程序和函数”一节中,介绍了MySQL存储程序的语法。
通过JDBC的CallableStatement接口,Connector/J指明了存储程序的功能。
在下面的示例中,给出了1个存储程序,它返回增量为1的inOutParam的值,并通过inputParam传递了作为ResultSet的字符串。
示例26.3. 存储程序示例
CREATE PROCEDURE demoSp(IN inputParam VARCHAR(255), INOUT inOutParam INT)
BEGIN
DECLARE z INT;
SET z = inOutParam + 1;
SET inOutParam = z;
SELECT inputParam;
SELECT CONCAT('zyxw', inputParam);
END
要想与Connector/J一起使用demoSp,可采取下述步骤:
1. 使用Connection.prepareCall()准备可调用语句。
注意,必须使用JDBC转义语法,而且必须使用包含占位符的圆括号:
示例26.4. 使用Connection.prepareCall()
导入java.sql.CallableStatement:
...
//
// Prepare a call to the stored procedure 'demoSp'
// with two parameters
//
// Notice the use of JDBC-escape syntax ({call ...})
//
CallableStatement cStmt = conn.prepareCall("{call demoSp(?, ?)}");
cStmt.setString(1, "abcdefg");
Connection.prepareCall()是一种开销很大的方法,原因在于驱动程序执行的支持输出参数的元数据检索。出于性能方面的原因,应在你的代码中再次使用CallableStatement实例,通过该方式,使对Connection.prepareCall()的不必要调用降至最低。
2. 注册输出参数(如果有的话)
为了检索输出参数的值(创建存储程序时指定为OUT或INOUT的参数),JDBC要求在CallableStatement接口中使用各种registerOutputParameter()方法来执行语句之前指定它们:
示例26.5. 注册输出参数
导入java.sql.Types:
...
//
// Connector/J supports both named and indexed
// output parameters. You can register output
// parameters using either method, as well
// as retrieve output parameters using either
// method, regardless of what method was
// used to register them.
//
// The following examples show how to use
// the various methods of registering
// output parameters (you should of course
// use only one registration per parameter).
//
//
// Registers the second parameter as output
//
cStmt.registerOutParameter(2);
//
// Registers the second parameter as output, and
// uses the type 'INTEGER' for values returned from
// getObject()
//
cStmt.registerOutParameter(2, Types.INTEGER);
//
// Registers the named parameter 'inOutParam'
//
cStmt.registerOutParameter("inOutParam");
//
// Registers the named parameter 'inOutParam', and
// uses the type 'INTEGER' for values returned from
// getObject()
//
cStmt.registerOutParameter("inOutParam", Types.INTEGER);
...
3. 设置输入参数(如果有的话)
输入以及输入/输出参数是作为PreparedStatement对象而设置的。但是,CallableStatement也支持按名称设置参数:
示例26.6. 设置CallableStatement输入参数
...
//
// Set a parameter by index
//
cStmt.setString(1, "abcdefg");
//
// Alternatively, set a parameter using
// the parameter name
//
cStmt.setString("inputParameter", "abcdefg");
//
// Set the 'in/out' parameter using an index
//
cStmt.setInt(2, 1);
//
// Alternatively, set the 'in/out' parameter
// by name
//
cStmt.setInt("inOutParam", 1);
...
4. 执行CallableStatement,并检索任何结果集或输出参数。
尽管CallableStatement支持调用任何语句执行方法(executeUpdate(),executeQuery()或execute()),最灵活的方法是调用execute(),这是因为,采用该方法,你无需事先知道存储程序是否将返回结果集:
示例26.7. 检索结果和输出参数值
...
boolean hadResults = cStmt.execute();
//
// Process all returned result sets
//
while (hadResults) {
ResultSet rs = cStmt.getResultSet();
// process result set
...
hadResults = cStmt.getMoreResults();
}
//
// Retrieve output parameters
//
// Connector/J supports both index-based and
// name-based retrieval
//
int outputValue = cStmt.getInt(1); // index-based
outputValue = cStmt.getInt("inOutParam"); // name-based
...