当 JDBC 遇上返回 Cursor

本文出处:https://www.modb.pro/db/400426

使用 jdbc 访问 PostgreSQL 或者 MogDB(openGauss)数据库里的 cursor 游标时,官方文档可查的资料较少,下面的示例供参考。

测试环境

JDBC:postgresql-42.3.5.jar

PG: 14.2

MogDB(openGauss): 3.0.0

测试背景

针对 function 和 procedure 返回 cursor 游标类型,通过 jdbc 如何调用。

测试 function:curtest1,通过 returns 返回游标类型

create or replace function curtest1()

returns refcursor

language plpgsql

as $function$

declare

cur refcursor;

begin

open cur for select id,data from fiverows;

return cur;

end;

$function$;

测试 procedure:curtest2,通过 out 参数返回游标类型

create or replace procedure curtest2(out cur refcursor)

language plpgsql

as $procedure$

begin

open cur for select id,data from fiverows;

end;

$procedure$;

测试 procedure:curtest3,通过 out 参数返回多个游标类型

create or replace procedure curtest3(out cur1 refcursor,out cur2 refcursor)

language plpgsql

as $procedure$

begin

open cur1 for select id,data from fiverows where id between 1 and 3;

open cur2 for select id,data from fiverows where id between 4 and 5;

end;

$procedure$;

表结构及数据

create table fiverows(id serial primary key,data text);

insert into fiverows(data) values('one'),('two'),

('three'),('four'),('five');

测试一:function 通过 returns 返回游标

function 返回游标在 PostgreSQL 或者 MogDB(openGauss)数据库里访问的代码参考如下:

public static void main(String[] args) throws Exception{
Class.forName("org.postgresql.Driver");
Connection conn = DriverManager.getConnection("jdbc:postgresql://***.***.***.***:1402/postgres","postgres","admin");
CallableStatement stmt = null;
ResultSet resultSet = null;
try{
conn.setAutoCommit(false);
stmt = conn.prepareCall("{? = call public.curtest1()}");;
stmt.registerOutParameter(1, Types.REF_CURSOR);
stmt.setCursorName("mycur1");
stmt.execute();
resultSet = (ResultSet) stmt.getObject(1);
while(resultSet.next()){
Integer id = (Integer)resultSet.getInt(1);
String data = (String) resultSet.getString(2);
System.out.println("id = "+id+", data = "+data);
} } catch (Exception e) {
e.printStackTrace();
}
conn.close();
}

注意下面这几点: 1.使用 CallableStatement 2.使用 Types.REF_CURSOR 注册输出参数 3.Statement 执行后,再通过 Statement 获取结果集

测试二:procedure 通过 out 参数返回游标

procedure 返回游标在 PostgreSQL 或者 MogDB(openGauss)数据库里有一点差异:主要是 escapeSyntaxCallMode 参数。

PostgreSQL

procedure 返回游标的 jdbc 代码跟上面 function 测试类似:

public static void main(String[] args) throws Exception{
Class.forName("org.postgresql.Driver");
Connection conn = DriverManager.getConnection("jdbc:postgresql://***.***.***.***:1402/postgres?escapeSyntaxCallMode=call", "postgres","admin");
CallableStatement stmt = null;
ResultSet resultSet = null;
try{
conn.setAutoCommit(false);
stmt = conn.prepareCall("{call public.curtest2(?)}");;
stmt.registerOutParameter(1, Types.REF_CURSOR); stmt.execute();
resultSet = (ResultSet) stmt.getObject(1);
while(resultSet.next()){
Integer id = (Integer)resultSet.getInt(1);
String data = (String) resultSet.getString(2);
System.out.println("id = "+id+", data = "+data);
}
} catch (Exception e) {
e.printStackTrace();
}
conn.close();
}

不过执行上面的代码客户端会报下面的错误:

错误信息提示并不是很明确,查找资料发现大概与 escapeSyntaxCallMode 参数有关,该参数的官方链接如下:https://jdbc.postgresql.org/documentation/head/connect.html

Specifies how the driver transforms JDBC escape call syntax into underlying SQL, for invoking procedures or functions. In escapeSyntaxCallMode=select mode (the default), the driver always uses a SELECT statement (allowing function invocation only). In escapeSyntaxCallMode=callIfNoReturn mode, the driver uses a CALL statement (allowing procedure invocation) if there is no return parameter specified, otherwise the driver uses a SELECT statement. In escapeSyntaxCallMode=call mode, the driver always uses a CALL statement (allowing procedure invocation only).

自 PostgreSQL v11 开始支持 procedure,PostgreSQL JDBC 驱动也配套引入了 escapeSyntaxCallMode 参数,该参数有三种值,默认是第一种 func,系统理解为 function 来调用;第二种是 call,系统理解为 procedure 来调用;第三种是系统根据定义自动猜测。

上面的 connection 连接串加上 escapeSyntaxCallMode 参数,修改成:

jdbc:postgresql://...:1402/postgres?escapeSyntaxCallMode=call

则可正常执行

MogDB(openGauss)

procedure 返回游标的 jdbc 代码与 function 测试类似,并且也不需要设置 escapeSyntaxCallMode 参数。

procedure 创建语法有差异,代码如下:

create or replace procedure curtest2(out cur refcursor) as begin open cur for select id,data from fiverows; end;

测试三:procedure 通过 out 参数返回多个游标

返回多个游标与测试二类似,也是同样支持,在 PostgreSQL 也是需要设置 escapeSyntaxCallMode 参数,MogDB(openGauss)不需要设置。

PostgreSQL

jdbc 代码如下:

public static void main(String[] args) throws Exception{
Class.forName("org.postgresql.Driver");
Connection conn = DriverManager.getConnection("jdbc:postgresql://***.***.***.***:1402/postgres?escapeSyntaxCallMode=call","postgres","admin");
CallableStatement stmt = null;
ResultSet resultSet = null;
try{
conn.setAutoCommit(false);
stmt = conn.prepareCall("{call public.curtest3(?,?)}");;
stmt.registerOutParameter(1, Types.REF_CURSOR);
stmt.registerOutParameter(2, Types.REF_CURSOR);
stmt.execute();
resultSet = (ResultSet) stmt.getObject(1);
System.out.println("cursor1 data:");
while(resultSet.next()){
Integer id = (Integer)resultSet.getInt(1);
String data = (String) resultSet.getString(2);
System.out.println("id = "+id+", data = "+data);
}
resultSet = (ResultSet) stmt.getObject(2);
System.out.println("cursor2 data:");
while(resultSet.next()){
Integer id = (Integer)resultSet.getInt(1);
String data = (String) resultSet.getString(2);
System.out.println("id = "+id+", data = "+data);
} } catch (Exception e) {
e.printStackTrace();
}
conn.close();
}

测试结果如下:

MogDB(openGauss)

与测试二类似,不需要设置 escapeSyntaxCallMode 参数。

procedure 创建语法有差异,代码如下:

create or replace procedure curtest3(out cur1 refcursor,out cur2 refcursor)

as

begin

open cur1 for select id,data from fiverows where id between 1 and 3;

open cur2 for select id,data from fiverows where id between 4 and 5;

end;

结论通过 jdbc 访问 function 里的 returns cursor 或者 procedure 里的 out cursor 类型都支持。 区别在于 procedure 的 out cursor 类型,在 PostgreSQL 需要设置 escapeSyntaxCallMode=call,MogDB(openGauss)数据库不需要。

当JDBC遇上返回Cursor的更多相关文章

  1. 谁还没遇上过NoClassDefFoundError咋地——浅谈字节码生成与热部署

    谁还没遇上过NoClassDefFoundError咋地--浅谈字节码生成与热部署 前言 在Java程序员的世界里,NoClassDefFoundError是一类相当令人厌恶的错误,因为这类错误通常非 ...

  2. dynamic遇上ADO.NET

    传说中的dynamic dynamic是个不合群.不按规则办事的家伙,可以说是个异形,但更恐怖的是它又是无所不知的,任何事情都难不了它(咳咳,它似乎与Lambda表达式是死对头).这令人想起<死 ...

  3. 前端遇上Go: 静态资源增量更新的新实践

    前端遇上Go: 静态资源增量更新的新实践https://mp.weixin.qq.com/s/hCqQW1F8FngPPGZAisAWUg 前端遇上Go: 静态资源增量更新的新实践 原创: 洋河 美团 ...

  4. 当微信小程序遇上filter~

    在微信小程序的开发过程中,当你想要实现不同页面间的数据绑定,却为此抓耳饶腮时,不妨让微信小程序与filter 来一场完美的邂逅,相信会给你带来别样的惊喜~ 前段时间被安利了一个很实用的公众号-前端早读 ...

  5. 当 Go struct 遇上 Mutex

    struct 是我们写 Go 必然会用到的关键字, 不过当 struct 遇上一些比较特殊类型的时候, 你注意过你的程序是否正常吗 ? 一段代码 type URL struct { Ip string ...

  6. 当 SQL Server(mssql-jdbc) 遇上 BigDecimal → 精度丢失,真坑!

    开心一刻 中午和哥们一起喝茶 哥们说道:晚上喝酒去啊 我:不去,我女朋友过生日 哥们瞪大眼睛看着我:你有病吧,充气的过什么生日 我生气到:有特么生产日期的好吧 需求背景 系统对接了外部系统,调用外部系 ...

  7. MVC遇上bootstrap后的ajax表单模型验证

    MVC遇上bootstrap后的ajax表单验证 使用bootstrap后他由他自带的样式has-error,想要使用它就会比较麻烦,往常使用jqueyr.validate的话只有使用他自己的样式了, ...

  8. 敏捷遇上UML-需求分析及软件设计最佳实践(郑州站 2014-6-7)

      邀请函: 尊敬的阁下:我们将在郑州为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实 ...

  9. 敏捷遇上UML—软创基地马年大会(广州站 2014-4-19)

        我们将在广州为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实战技巧. 时间:2 ...

  10. 敏捷遇上UML——软创基地马年大会(深圳站 2014-3-15)

    邀请函: 尊敬的阁下: 我们将在深圳为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实战 ...

随机推荐

  1. Huggingface初上手即ERNIE-gram句子相似性实战

    大模型如火如荼的今天,不学点语言模型(LM)相关的技术实在是说不过去了.只不过由于过往项目用到LM较少,所以学习也主要停留在直面--动眼不动手的水平.Huggingface(HF)也是现在搞LM离不开 ...

  2. 探索浏览器录屏Web API 接口的应用前景与限制

    一.浏览器录屏Web API 接口的优点: 简化录屏流程:浏览器录屏Web API 接口可以直接在网页中调用,无需安装额外的插件或软件,简化了录屏的流程. 实时录制与传输:Web API 接口可以实时 ...

  3. C++ STL 容器-Deque

    C++ STL 容器-Deque std::deque(双端队列)是C++标准模板库(STL)中的一个容器,它支持在序列的两端快速插入和删除元素.与std::vector和std::list等其他序列 ...

  4. 19 SWERC 2022-2023 - Online Mirror (Unrated, ICPC Rules, Teams Preferred)L. Controllers(数学公式+瞎搞)

    L. Controllers 思路: #include <bits/stdc++.h> #define int long long #define rep(i, a, b) for(int ...

  5. 深入理解与应用CSS clip-path 属性

    clip-path clip-path是什么 clip-path 是一个CSS属性,允许开发者创建一个剪切区域,从而决定元素的哪些部分可见,哪些部分会被隐藏.通过定义这个剪切路径(clipping p ...

  6. AMD Intel CPU 对比图

  7. 【数据结构】C语言实现动态扩容数组

    // resizable array /* Think about a set of functions that provide a mechanism of resizable array of ...

  8. 一个简单的HTTP服务器的实现

    我们继续我们的HTTP服务器的实现(使用别的代码来实现), 这个HTTP服务器的实现,我们主要就是关注TCP服务器中的recv还有send的处理. 首先,看一下HTTP,我们在用浏览器访问我们的TCP ...

  9. 实时渲染大赛结果将于3月31日晚8点B站直播公布,敬请期待!

    根据评选标准,经过评委组层层选拔,首届实时渲染3D动画创作大赛,最终获奖结果出炉啦! 本次赛事报名人数达212人,入围作品共40份,其中Omniverse组11份,专业组15份,学生组14份. 我们将 ...

  10. App启动流程

    目录介绍 1.什么是Zygote进程 1.1 简单介绍 1.2 各个进程的先后顺序 1.3 进程作用说明 2.Zygote进程的启动流程 2.1 源码位置 2.2 ZygoteInit类的main方法 ...