在Java开发中,通过JDBC调用数据库存储过程是常见的数据库操作场景,掌握相关的实战技巧能够提升开发效率,减少重复的SQL编写工作。存储过程是预先编译并存储在数据库中的SQL语句集合,通过Java调用可以直接复用数据库端已经实现的逻辑,同时降低网络传输开销。

调用存储过程的核心类
Java中调用存储过程主要依赖CallableStatement接口,它是PreparedStatement的子接口,专门用于执行SQL存储过程。使用JDBC调用存储过程的基本步骤分为四步:首先加载数据库驱动,然后建立数据库连接,接着创建CallableStatement对象并绑定存储过程参数,最后执行存储过程并处理返回结果。
基础调用流程示例
以下以MySQL数据库为例,假设数据库中已经存在名为add_user的存储过程,该存储过程接收两个输入参数用户名和用户年龄,执行插入用户数据的操作,无返回值。调用该存储过程的基础代码如下:
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class CallProcedureDemo {
public static void main(String[] args) {
// 数据库连接信息
String url = "jdbc:mysql://127.0.0.1:3306/test_db?useSSL=false&serverTimezone=UTC";
String username = "root";
String password = "123456";
Connection conn = null;
CallableStatement cs = null;
try {
// 1. 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2. 建立连接
conn = DriverManager.getConnection(url, username, password);
// 3. 创建CallableStatement,{call 存储过程名(参数占位符)}是固定语法
String sql = "{call add_user(?, ?)}";
cs = conn.prepareCall(sql);
// 设置输入参数,第一个参数是占位符索引,第二个是参数值
cs.setString(1, "张三");
cs.setInt(2, 25);
// 4. 执行存储过程
cs.execute();
System.out.println("存储过程调用成功,用户数据已插入");
} catch (ClassNotFoundException e) {
System.out.println("数据库驱动加载失败");
e.printStackTrace();
} catch (SQLException e) {
System.out.println("存储过程调用失败");
e.printStackTrace();
} finally {
// 关闭资源
try {
if (cs != null) {
cs.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}处理不同参数类型的存储过程
存储过程的参数分为输入参数(IN)、输出参数(OUT)和输入输出参数(INOUT)三种类型,不同类型的参数处理方式有所区别。
带输出参数的存储过程调用
如果存储过程存在输出参数,需要在创建CallableStatement之后,执行之前注册输出参数的类型。假设存在名为get_user_count的存储过程,无输入参数,输出参数为用户总数,类型为INT,调用代码如下:
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Types;
public class CallOutProcedureDemo {
public static void main(String[] args) {
String url = "jdbc:mysql://127.0.0.1:3306/test_db?useSSL=false&serverTimezone=UTC";
String username = "root";
String password = "123456";
Connection conn = null;
CallableStatement cs = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
conn = DriverManager.getConnection(url, username, password);
// 存储过程无输入参数,只有一个输出参数占位符
String sql = "{call get_user_count(?)}";
cs = conn.prepareCall(sql);
// 注册输出参数,第一个参数是占位符索引,第二个是参数类型
cs.registerOutParameter(1, Types.INTEGER);
cs.execute();
// 获取输出参数的值
int userCount = cs.getInt(1);
System.out.println("当前用户总数为:" + userCount);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (cs != null) {
cs.close();
}
if (conn != null) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}带输入输出参数的存储过程调用
对于INOUT类型的参数,需要先设置输入值,再注册参数类型,执行后获取输出值。假设存储过程update_user_age接收一个用户ID作为输入,同时返回更新后的用户年龄,调用方式如下:
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Types;
public class CallInOutProcedureDemo {
public static void main(String[] args) {
String url = "jdbc:mysql://127.0.0.1:3306/test_db?useSSL=false&serverTimezone=UTC";
String username = "root";
String password = "123456";
Connection conn = null;
CallableStatement cs = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
conn = DriverManager.getConnection(url, username, password);
String sql = "{call update_user_age(?, ?)}";
cs = conn.prepareCall(sql);
// 设置IN部分的输入值
cs.setInt(1, 1001);
// 注册INOUT参数的类型
cs.registerOutParameter(2, Types.INTEGER);
// 设置INOUT参数的输入值
cs.setInt(2, 30);
cs.execute();
// 获取INOUT参数的输出值
int newAge = cs.getInt(2);
System.out.println("用户ID为1001的用户更新后年龄为:" + newAge);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (cs != null) {
cs.close();
}
if (conn != null) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}实战注意事项
- 调用存储过程的SQL语法固定为
{call 存储过程名(参数列表)},参数占位符用问号表示,数量要和存储过程定义的参数数量一致。 - 输出参数必须在执行前通过
registerOutParameter方法注册类型,类型要和数据库存储过程定义的参数类型匹配,否则会报错。 - 资源关闭要放在finally块中,避免因为异常导致连接、语句对象无法释放,引发数据库连接耗尽的问题。
- 如果存储过程返回结果集,可以通过
CallableStatement的getResultSet方法获取,处理方式和处理普通查询的结果集一致。
以上就是Java中通过JDBC调用SQL存储过程的完整实战技巧,掌握这些内容就可以应对大部分项目中调用存储过程的需求,开发者可以根据实际存储过程的定义调整参数处理逻辑。
JDBC存储过程SQL语言Java数据库交互CallableStatement修改时间:2026-06-07 00:49:36