PostgreSQL JDBC驱动(pgjdbc)存储过程与函数调用指南
概述
PostgreSQL JDBC驱动(pgjdbc)为Java应用程序提供了与PostgreSQL数据库交互的能力。本文将深入讲解如何使用该驱动调用PostgreSQL中的存储函数和存储过程,这是数据库开发中的核心技能之一。
存储函数与存储过程的区别
PostgreSQL支持两种存储对象:
- 存储函数(Functions):可以返回值,传统上用于计算和查询
- 存储过程(Procedures):从PostgreSQL 11开始支持,可以执行事务控制,更适合数据修改操作
基本调用语法
两种存储对象都使用JDBC的CallableStatement
接口调用,标准语法为:
{call 存储对象名(?)}
连接参数配置
escapeSyntaxCallMode
参数控制驱动如何处理调用语法:
select
(默认):保持向后兼容,仅支持函数调用callIfNoReturn
:推荐新项目使用,根据是否有返回值自动选择函数或过程
存储函数调用示例
基本函数调用
// 调用内置upper函数将字符串转为大写
CallableStatement upperFunc = conn.prepareCall("{? = call upper( ? ) }");
upperFunc.registerOutParameter(1, Types.VARCHAR);
upperFunc.setString(2, "lowercase to uppercase");
upperFunc.execute();
String upperCased = upperFunc.getString(1);
upperFunc.close();
返回结果集的函数
PostgreSQL函数可以通过两种方式返回结果集:
1. 返回SETOF类型
// 创建返回整数集合的函数
Statement stmt = conn.createStatement();
stmt.execute("CREATE OR REPLACE FUNCTION setoffunc() RETURNS SETOF int AS " +
"' SELECT 1 UNION SELECT 2;' LANGUAGE sql");
// 使用普通查询方式调用
ResultSet rs = stmt.executeQuery("SELECT * FROM setoffunc()");
while (rs.next()) {
// 处理结果
}
rs.close();
stmt.close();
2. 返回refcursor(游标)
// 必须在事务中调用
conn.setAutoCommit(false);
// 准备返回游标的函数
Statement stmt = conn.createStatement();
stmt.execute("CREATE OR REPLACE FUNCTION refcursorfunc() RETURNS refcursor AS '" +
" DECLARE mycurs refcursor; " +
" BEGIN OPEN mycurs FOR SELECT 1 UNION SELECT 2; RETURN mycurs; END;' language plpgsql");
stmt.close();
// 调用函数并获取结果集
CallableStatement func = conn.prepareCall("{? = call refcursorfunc() }");
func.registerOutParameter(1, Types.OTHER);
func.execute();
ResultSet results = (ResultSet) func.getObject(1);
while (results.next()) {
// 处理结果
}
results.close();
func.close();
存储过程调用示例
存储过程适合执行包含事务的操作:
// 配置连接参数
Properties props = new Properties();
props.setProperty("escapeSyntaxCallMode", "callIfNoReturn");
Connection con = DriverManager.getConnection(url, props);
// 准备测试表和存储过程
Statement stmt = con.createStatement();
stmt.execute("CREATE TEMP TABLE temp_val ( some_val bigint )");
stmt.execute("CREATE OR REPLACE PROCEDURE commitproc(a INOUT bigint) AS '" +
" BEGIN INSERT INTO temp_val values(a); COMMIT; END;' LANGUAGE plpgsql");
stmt.close();
// 必须在自动提交模式下调用
con.setAutoCommit(true);
// 调用存储过程
CallableStatement proc = con.prepareCall("{call commitproc( ? )}");
proc.setInt(1, 100);
proc.execute();
proc.close();
性能注意事项
- 当前版本的JDBC驱动在处理refcursor返回的结果集时,会一次性获取所有数据到客户端内存,忽略fetch size设置
- 对于大数据集,考虑使用SETOF返回方式或直接处理游标名称
最佳实践
- 新项目建议设置
escapeSyntaxCallMode=callIfNoReturn
- 明确区分函数和过程的使用场景:计算用函数,数据修改用过程
- 注意事务边界:函数通常在事务内调用,过程可能需要独立事务
通过掌握这些技巧,您可以充分利用PostgreSQL JDBC驱动高效地调用数据库中的存储逻辑。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考