当 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. 连接 AI,NebulaGraph Python ORM 项目 Carina 简化 Web 开发

    作者:Steam & Hao 本文整理自社区第 7 期会议中 13'21″ 到 44'11″ 的 Python ORM 的分享,视频见 https://www.bilibili.com/vid ...

  2. MVVM框架模式

    MVC框架模式 MVP框架模式 MVVM框架模式 MVVM模式即: 1.Model:数据层.网络数据操作,file文件操作,本地数据库操作: 2.View:视图层.布局加载,ui交互. 3.ViewM ...

  3. 当未指定且存在多个构造器,实例化对象时Spring如何选择?

    前言 在前面的讲解中,我们了解了如何获取构造器.当只有一个符合条件的构造器时,自然会选择它作为初始化的构造器.然而,在上一节中,我们遇到了一种特殊情况:当有多个符合条件的构造器时,返回的是一个数组.在 ...

  4. .Net Core中使用DiagnosticSource进行日志记录

    System.Diagnostics.DiagnosticSource 是一个可以对代码进行检测的模块,可以丰富地记录程序中地日志,包括可序列化的类型(例如 HttpResponseMessage 或 ...

  5. arch安装deep-wine-wechat时,跳过md5检测的方法

    yay -S --mflags --skipinteg deepin-wine-wechat 这条命令是的我们跳过了md5检测! 微信的安装位置:C:\Program Files\Tencent\We ...

  6. python处理txt文件常用方法总结

    一 打开txt的正确方式 一般人会用到怎么快速打开txt,下面分享两种方式: f = open("data.txt","r") #设置文件对象 f.close( ...

  7. Vue 长文本组件(有展开更多按钮)实现 附源码及使用

    原文地址:Vue 长文本组件(有展开更多按钮) | Stars-One的杂货小窝 最近项目需要优化长文本的显示,如果长文本过长,固定显示几行并显示一个展开更多的按钮,点击按钮即可把隐藏的文本显示出来 ...

  8. Spring之事务传播属性

    在Spring中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量. 在使用Spring时,大部分会用到他的声明式事务,简单的在配置文件中进行一些规则 ...

  9. Ubuntu 14.04傻瓜式安装 0@0

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文作为本人csdn blog的主站的备份.(Bl ...

  10. CAST电子部单片机方向授课——串口通信 预习文档

    CAST电子部单片机方向授课--串口通信 预习文档 课前小准备 安装串口调试助手 第一步:进入Microsoft Store 第二步:在Microsoft Store中搜索 "串口调试助手& ...