Postgres查询结果集的获取方法及其优缺点

Stella981
• 阅读 417

PG jdbc的查询结果集获取方式

1 简单全部结果集查询

默认情况下,pgjdbc是一次获取全部查询结果的,并且结果集的类型和并发性分别为ResultSet.TYPE_FORWARD_ONLY和ResultSet.CONCUR_READ_ONLY。也就是pgjdbc默认会一次获取全部查询结果,只能从前往后取,是只读的。

     stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);     rs = stmt.executeQuery(sql);     while(rs.next())     {             ...     }

通过修改结果集的类型和并发性,还分别可以获得(不)可滑动的,对变化(不)敏感的,(不)可更新的结果集。

ResultSet类型API: http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html#TYPE_SCROLL_SENSITIVE

ResultSet.TYPE_FORWARD_ONLY                        ResultSet.CONCUR_READ_ONLY

ResultSet.TYPE_SCROLL_INSENSITIVE                  ResultSet.CONCUR_UPDATABLE

ResultSet.TYPE_SCROLL_SENSITIVE

该方法一次获取全部结果:对于数据量小的查询来说,速度更快,结果集有多种灵活的获取方式;但对于数据量很大的查询,容易造成很大的内存消耗,甚至内存溢出。

2  基于游标的批量结果集查询

通过设置setFetchSize(int size)获取基于游标cursor的结果集,size>0表示开启游标,一次只获取size行结果集,该size取完后在获取下一size的结果集;size=0表示关闭游标,结果集一次取出全部行。

基于游标的结果集的使用是有条件的,如果不满足条件setFechSize(int size)将不起作用,pgjdbc还是会一次获取全部结果集。基于游标的结果集使用条件如下:

1.连到数据库服务的连接必须是基于V3协议的,V3协议是7.4及更新版本PG才能支持的,并且是他们的默认协议;

2.Connection必须是非自动提交模式.后端会在事务的结束的时候关闭游标,所以,在自动提交模式里,还没从游标里获取任何东西的时候,后端就已经把游标关闭了。

3.Statement必须以ResultSet.TYPE_FORWARD_ONLY的类型来创建,该结果集类型是默认的,所以可以直接使用stmt = conn.createStatement()来创建(或者stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY)).因此基于游标的结果集是只能向前获取,不能向后或者跳跃获取的。

4. 查询sql语句必须是一个单一的语句,不能是由分好分隔的多个语句。

// make sure autocommit is off
conn.setAutoCommit(false);
Statement st = conn.createStatement();
// Turn use of the cursor on.
st.setFetchSize(50);ResultSet 
rs = st.executeQuery("SELECT * FROM mytable");
while (rs.next())
{  
    System.out.print("a row was returned.");
}
rs.close();

// Turn the cursor off.
st.setFetchSize(0);
rs = st.executeQuery("SELECT * FROM mytable");
while (rs.next())
{   
    System.out.print("many rows were returned.");
}
rs.close();

该方法分批获取结果集,一次仅获取一个批量的数据,只有一个小批量的行集缓存在连接的客户端,当该批量用尽后才会通过重定位游标来获取下一批量的行集:对于数据量小的查询,由于分批获取,会导致查询速度降低,结果集取得的灵活性也不可用了;但是对于数据量大的查询,分批获取,首次获得结果的速度加快,降低了内存的消耗的阀值,可以避免内存溢出的问题。

桥哥的博客:[http://blog.chinaunix.net/uid-20726500-id-4844406.html](https://www.oschina.net/action/GoToLink?url=http%3A%2F%2Fblog.chinaunix.net%2Fuid-20726500-id-4844406.html)

JAVA API:  http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html#TYPE_SCROLL_SENSITIVE

PG JDBC Last Doc: https://jdbc.postgresql.org/documentation/head/query.html#query-with-cursor

原文如下:

Chapter 5. Issuing a Query and Processing the Result

Table of Contents

    Getting results based on a cursor

    Using the Statement or PreparedStatement Interface

    Using the ResultSet Interface

    Performing Updates

    Creating and Modifying Database Objects

Any time you want to issue SQL statements to the database, you require a Statement or PreparedStatement instance. Once you have a Statement or PreparedStatement, you can use issue a query. This will return a ResultSet instance, which contains the entire result (see the section called “Getting results based on a cursor” here for how to alter this behaviour). Example 5.1, “Processing a Simple Query in JDBC” illustrates this process.

Example 5.1. Processing a Simple Query in JDBC

This example will issue a simple query and print out the first column of each row using a Statement.

Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT * FROM mytable WHERE columnfoo = 500");
while (rs.next())
{
   System.out.print("Column 1 returned ");
   System.out.println(rs.getString(1));
} rs.close();
st.close();

This example issues the same query as before but uses a PreparedStatement and a bind value in the query.

int foovalue = 500;
PreparedStatement st = conn.prepareStatement("SELECT * FROM mytable WHERE columnfoo = ?");
st.setInt(1, foovalue);
ResultSet rs = st.executeQuery();
while (rs.next())
{
   System.out.print("Column 1 returned ");
   System.out.println(rs.getString(1));
}
rs.close();
st.close();

Getting results based on a cursor

By default the driver collects all the results for the query at once. This can be inconvenient for large data sets so the JDBC driver provides a means of basing a ResultSet on a database cursor and only fetching a small number of rows.

A small number of rows are cached on the client side of the connection and when exhausted the next block of rows is retrieved by repositioning the cursor.

Note

Cursor based ResultSets cannot be used in all situations. There a number of restrictions which will make the driver silently fall back to fetching the whole ResultSet at once.

The connection to the server must be using the V3 protocol. This is the default for (and is only supported by) server versions 7.4 and later.

The Connection must not be in autocommit mode. The backend closes cursors at the end of transactions, so in autocommit mode the backend will have closed the cursor before anything can be fetched from it. *The Statement must be created with a ResultSet type of ResultSet.TYPE_FORWARD_ONLY. This is the default, so no code will need to be rewritten to take advantage of this, but it also means that you cannot scroll backwards or otherwise jump around in the ResultSet.

The query given must be a single statement, not multiple statements strung together with semicolons.

Example 5.2. Setting fetch size to turn cursors on and off.

Changing code to cursor mode is as simple as setting the fetch size of the Statement to the appropriate size. Setting the fetch size back to 0 will cause all rows to be cached (the default behaviour).

// make sure autocommit is off
conn.setAutoCommit(false);
Statement st = conn.createStatement();
// Turn use of the cursor on.
st.setFetchSize(50);
ResultSet rs = st.executeQuery("SELECT * FROM mytable");
while (rs.next())
{
   System.out.print("a row was returned.");
}
rs.close();

// Turn the cursor off.
st.setFetchSize(0);
rs = st.executeQuery("SELECT * FROM mytable");
while (rs.next())
{
   System.out.print("many rows were returned.");
}
rs.close();
// Close the statement.
st.close();
点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
添砖java的啾 添砖java的啾
2年前
distinct效率更高还是group by效率更高?
目录00结论01distinct的使用02groupby的使用03distinct和groupby原理04推荐groupby的原因00结论先说大致的结论(完整结论在文末):在语义相同,有索引的情况下groupby和distinct都能使用索引,效率相同。在语义相同,无索引的情况下:distinct效率高于groupby。原因是di
红烧土豆泥 红烧土豆泥
2年前
MyBatis之ResultMap玩法回顾
1、SelectResultMap自定义结果集映射规则xmlselectfromemployeewhereidid关联查询级联属性封装结果xmlselectfromemployeee,departmentdwheree.idd.id关联查询associatio
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
Java日期时间API系列31
  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这