从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 ...