文章目录
- 1、简述
- 2、类图
- 3、示例
- 3.1、单个结果集
- 3.2、多个结果集
- 3.3、带参数的存储过程
- 3.3.1、带有输入参数(IN)的存储过程
- 3.3.2、带有输出参数(OUT)的存储过程
1、简述
CallableStatement 是用于执行SQL存储过程的。JDBC API提供了存储过程SQL转义语法,该语法允许所有RDBMS以标准方式调用存储过程。
Connection 接口提供了 prepareCall(String SQL)方法来创建 CallableStatement 对象,以调用数据库存储过程。 CallableStatement对象提供了用于设置其IN和OUT参数的方法,以及用于执行对存储过程的调用的方法。
2、类图
下面的类图显示了 CallableStatement 接口的继承关系:
CallableStatement 使用从 PreparedStatement继承的set方法设置IN参数值。 在执行存储过程之前,必须先注册所有OUT参数的类型。 它们的值在执行后通过此处提供的get方法检索。
一个CallableStatement可以返回一个ResultSet对象或多个ResultSet对象。 使用从Statement继承的操作来处理多个ResultSet对象。
3、示例
3.1、单个结果集
返回单个结果集的存储过程
DELIMITER $$
USE `lkf_db`$$
CREATE PROCEDURE `proc_single_select` ()
BEGIN
SELECT * FROM users;
END$$
DELIMITER ;
以下程序演示了如何调用 proc_single_select() 存储过程并生成单个结果集。
//数据库连接地址
private final String jdbcUrl = "jdbc:mysql://localhost:3306/lkf_db?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT";
//用户名
private final String username = "root";
//密码
private final String password = "root";
//调用返回单个结果集存储过程语句
private final String proc_single_select_sql = "call proc_single_select()";
//调用返回多个结果集存储过程语句
private final String proc_multi_select_sql = "call proc_multi_select()";
public static void main(String[] args) {
CallableStatementDemo callableStatementDemo = new CallableStatementDemo();
//返回单个结果集
callableStatementDemo.singleResultSet();
}
/**
* 返回单个结果集
*/
public void singleResultSet() {
try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password);
CallableStatement stmt = conn.prepareCall(proc_single_select_sql);
ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
System.out.println("ID = " + rs.getInt(1) + ", NAME = " + rs.getString(2) + ", Email = " +
rs.getString(3) + ", Country = " + rs.getString(4) + ", Password = " + rs.getString(5));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
结果:
ID = 1, NAME = 张三, Email = zhangsan@qq.com, Country = china, Password = 123456
ID = 2, NAME = 李四, Email = lisi@qq.com, Country = china, Password = 123456
3.2、多个结果集
返回多个结果集的存储过程
DELIMITER $$
USE `lkf_db`$$
CREATE PROCEDURE `proc_multi_select` ()
BEGIN
#查询 id 为 1,按名字去重后的名字
SELECT DISTINCT NAME FROM users WHERE id = 1;
#按邮箱去重,并获取去重后的所有邮箱
SELECT DISTINCT email FROM users;
#根据id统计用户数量
SELECT COUNT(id) AS users_count FROM users;
END$$
DELIMITER ;
以下程序演示了如何调用 proc_multi_select() 存储过程并生成多个结果集。
//数据库连接地址
private final String jdbcUrl = "jdbc:mysql://localhost:3306/lkf_db?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT";
//用户名
private final String username = "root";
//密码
private final String password = "root";
//调用返回单个结果集存储过程语句
private final String proc_single_select_sql = "call proc_single_select()";
//调用返回多个结果集存储过程语句
private final String proc_multi_select_sql = "call proc_multi_select()";
public static void main(String[] args) {
CallableStatementDemo callableStatementDemo = new CallableStatementDemo();
//返回单个结果集
// callableStatementDemo.singleResultSet();
//返回多个结果集
callableStatementDemo.multipleResultSet();
}
/**
* 返回多个结果集
*/
public void multipleResultSet() {
try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password);
CallableStatement stmt = conn.prepareCall(proc_multi_select_sql);) {
//执行存储过程
boolean hasRs = stmt.execute();
System.out.println();
// 解析名字的结果集
if (hasRs) {
try (ResultSet rs = stmt.getResultSet()) {
while (rs.next()) {
System.out.println("NAME = " + rs.getString(1));
}
}
}
// 解析邮箱的结果集
if (stmt.getMoreResults()) {
try (ResultSet rs = stmt.getResultSet()) {
if (rs.next()) {
System.out.println("Email = " + rs.getString(1));
}
}
}
// 获取统计的用户数量
if (stmt.getMoreResults()) {
try (ResultSet rs = stmt.getResultSet()) {
if (rs.next()) {
System.out.println("Users count = " + rs.getInt(1));
}
}
}
} catch (SQLException e) {
e.printStackTrace();
}
}
结果:
NAME = 张三
Email = zhangsan@qq.com
Users count = 2
3.3、带参数的存储过程
存在三种类型的参数:IN,OUT和INOUT。
PreparedStatement对象只使用IN参数。 CallableStatement对象可以使用上面三种类型参数。
参数 | 描述 |
IN | 表示调用者传入值(传入值可以是字面量或变量)。创建SQL语句时其参数值是未知的。 使用 |
OUT | 表示过程向调用者传出值(可以返回多个值)(传出值只能是变量)。可以使用 |
INOUT | 既表示调用者向过程传入值,又表示过程向调用者传出值(值只能是变量)。使用 |
使用 IN 参数,只需遵循适用 于PreparedStatement 对象的相同规则,与绑定的Java数据类型相对应的setXXX()方法。
使用 OUT 和 INOUT 参数时,必须使用 CallableStatement 对象的方法 registerOutParameter()。
registerOutParameter() 方法将JDBC数据类型绑定到存储过程预期返回的数据类型。
当调用存储过程后,可以使用适当的 getXXX() 方法从OUT参数中检索该值。 此方法将检索到的SQL类型的值转换为Java 数据类型。
3.3.1、带有输入参数(IN)的存储过程
DELIMITER $$
USE `lkf_db`$$
CREATE PROCEDURE `proc_getUserByName` (IN p_name VARCHAR(30))
BEGIN
SELECT * FROM users WHERE NAME=p_name;
END$$
DELIMITER ;
以下示例将调用存储过程 proc_getUserByName 并传入参数,获取对应的记录信息。
private final String proc_in_select_sql = "call proc_getUserByName(?)";
/**
* 带有输入参数(IN)的存储过程
*/
public void procInParam() throws SQLException {
Connection conn = null;
CallableStatement stmt = null;
ResultSet rs = null;
try {
//获取连接对象
conn = DriverManager.getConnection(jdbcUrl, username, password);
//预编译
stmt = conn.prepareCall(proc_in_select_sql);
//传递输入参数
stmt.setString(1, "张三");
//执行存储过程
rs = stmt.executeQuery();
while (rs.next()) {
System.out.println("ID = " + rs.getInt(1) + ", NAME = " + rs.getString(2) + ", Email = " +
rs.getString(3) + ", Country = " + rs.getString(4) + ", Password = " + rs.getString(5));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (rs != null) {
rs.close();
stmt.close();
conn.close();
}
}
}
结果:
ID = 1, NAME = 张三, Email = zhangsan@qq.com, Country = china, Password = 123456
3.3.2、带有输出参数(OUT)的存储过程
DELIMITER $$
USE `lkf_db`$$
CREATE PROCEDURE `proc_getUserNumByName` (IN p_name VARCHAR(30),OUT p_userNum INT)
BEGIN
SELECT COUNT(id) FROM users WHERE NAME=p_name INTO p_userNum;
END$$
DELIMITER ;
以下示例,将调用具有输入和输出参数的存储过程 proc_getUserNumByName 获取满足指定条件的用户数量。
private final String proc_out_select_sql = "call proc_getUserNumByName(?,?)";
/**
* 带有输出参数(OUT)的存储过程
*/
public void procOutParam() throws SQLException {
Connection conn = null;
CallableStatement stmt = null;
ResultSet rs = null;
try {
//获取连接对象
conn = DriverManager.getConnection(jdbcUrl, username, password);
//预编译
stmt = conn.prepareCall(proc_out_select_sql);
//传递输入参数
stmt.setString(1, "张三");
//设置输出参数(注册输出参数)
/**
* 参数一: 参数位置
* 参数二: 存储过程中的输出参数的jdbc类型
*/
stmt.registerOutParameter(2, Types.INTEGER);
//执行存储过程
rs = stmt.executeQuery();
/**
* 得到输出参数的值
* 索引值: 预编译sql中的输出参数的位置
* getXX方法专门用于获取存储过程中的输出参数
*/
Integer result = stmt.getInt(2);
System.out.println(result);
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (rs != null) {
rs.close();
stmt.close();
conn.close();
}
}
}