本文主要解析一下pg jdbc statement的maxRows参数

Statement.setMaxRows

void setMaxRows(int max)

throws SQLException

Sets the limit for the maximum number of rows that any ResultSet object generated by this Statement object can contain to the given number. If the limit is exceeded, the excess rows are silently dropped.

Parameters:

max - the new max rows limit; zero means there is no limit

Throws:

SQLException - if a database access error occurs, this method is called on a closed Statement or the condition max >= 0 is not satisfied

See Also:

getMaxRows()

Statement.executeQuery

connection.getQueryExecutor().execute(queryToExecute, queryParameters, handler, maxrows,

fetchSize, flags);

最后是调用QueryExecutorImpl.execute(),然后它又是调用了

postgresql-9.4.1212.jre7-sources.jar!/org/postgresql/core/v3/QueryExecutorImpl.java

// sendOneQuery sends a single statement via the extended query protocol.

// Per the FE/BE docs this is essentially the same as how a simple query runs

// (except that it generates some extra acknowledgement messages, and we

// can send several queries before doing the Sync)

//

// Parse S_n from "query string with parameter placeholders"; skipped if already done previously

// or if oneshot

// Bind C_n from S_n plus parameters (or from unnamed statement for oneshot queries)

// Describe C_n; skipped if caller doesn't want metadata

// Execute C_n with maxRows limit; maxRows = 1 if caller doesn't want results

// (above repeats once per call to sendOneQuery)

// Sync (sent by caller)

//

private void sendOneQuery(SimpleQuery query, SimpleParameterList params, int maxRows,

int fetchSize, int flags) throws IOException {

boolean asSimple = (flags & QueryExecutor.QUERY_EXECUTE_AS_SIMPLE) != 0;

if (asSimple) {

assert (flags & QueryExecutor.QUERY_DESCRIBE_ONLY) == 0

: "Simple mode does not support describe requests. sql = " + query.getNativeSql()

+ ", flags = " + flags;

sendSimpleQuery(query, params);

return;

}

assert !query.getNativeQuery().multiStatement

: "Queries that might contain ; must be executed with QueryExecutor.QUERY_EXECUTE_AS_SIMPLE mode. "

+ "Given query is " + query.getNativeSql();

// nb: if we decide to use a portal (usePortal == true) we must also use a named statement

// (oneShot == false) as otherwise the portal will be closed under us unexpectedly when

// the unnamed statement is next reused.

boolean noResults = (flags & QueryExecutor.QUERY_NO_RESULTS) != 0;

boolean noMeta = (flags & QueryExecutor.QUERY_NO_METADATA) != 0;

boolean describeOnly = (flags & QueryExecutor.QUERY_DESCRIBE_ONLY) != 0;

boolean usePortal = (flags & QueryExecutor.QUERY_FORWARD_CURSOR) != 0 && !noResults && !noMeta

&& fetchSize > 0 && !describeOnly;

boolean oneShot = (flags & QueryExecutor.QUERY_ONESHOT) != 0 && !usePortal;

boolean noBinaryTransfer = (flags & QUERY_NO_BINARY_TRANSFER) != 0;

boolean forceDescribePortal = (flags & QUERY_FORCE_DESCRIBE_PORTAL) != 0;

// Work out how many rows to fetch in this pass.

int rows;

if (noResults) {

rows = 1; // We're discarding any results anyway, so limit data transfer to a minimum

} else if (!usePortal) {

rows = maxRows; // Not using a portal -- fetchSize is irrelevant

} else if (maxRows != 0 && fetchSize > maxRows) {

// fetchSize > maxRows, use maxRows (nb: fetchSize cannot be 0 if usePortal == true)

rows = maxRows;

} else {

rows = fetchSize; // maxRows > fetchSize

}

sendParse(query, params, oneShot);

// Must do this after sendParse to pick up any changes to the

// query's state.

//

boolean queryHasUnknown = query.hasUnresolvedTypes();

boolean paramsHasUnknown = params.hasUnresolvedTypes();

boolean describeStatement = describeOnly

|| (!oneShot && paramsHasUnknown && queryHasUnknown && !query.isStatementDescribed());

if (!describeStatement && paramsHasUnknown && !queryHasUnknown) {

int queryOIDs[] = query.getStatementTypes();

int paramOIDs[] = params.getTypeOIDs();

for (int i = 0; i < paramOIDs.length; i++) {

// Only supply type information when there isn't any

// already, don't arbitrarily overwrite user supplied

// type information.

if (paramOIDs[i] == Oid.UNSPECIFIED) {

params.setResolvedType(i + 1, queryOIDs[i]);

}

}

}

if (describeStatement) {

sendDescribeStatement(query, params, describeOnly);

if (describeOnly) {

return;

}

}

// Construct a new portal if needed.

Portal portal = null;

if (usePortal) {

String portalName = "C_" + (nextUniqueID++);

portal = new Portal(query, portalName);

}

sendBind(query, params, portal, noBinaryTransfer);

// A statement describe will also output a RowDescription,

// so don't reissue it here if we've already done so.

//

if (!noMeta && !describeStatement) {

/*

* don't send describe if we already have cached the row description from previous executions

*

* XXX Clearing the fields / unpreparing the query (in sendParse) is incorrect, see bug #267.

* We might clear the cached fields in a later execution of this query if the bind parameter

* types change, but we're assuming here that they'll still be valid when we come to process

* the results of this query, so we don't send a new describe here. We re-describe after the

* fields are cleared, but the result of that gets processed after processing the results from

* earlier executions that we didn't describe because we didn't think we had to.

*

* To work around this, force a Describe at each execution in batches where this can be a

* problem. It won't cause more round trips so the performance impact is low, and it'll ensure

* that the field information available when we decoded the results. This is undeniably a

* hack, but there aren't many good alternatives.

*/

if (!query.isPortalDescribed() || forceDescribePortal) {

sendDescribePortal(query, portal);

}

}

sendExecute(query, portal, rows);

}

重点看这段

// Work out how many rows to fetch in this pass.

int rows;

if (noResults) {

rows = 1; // We're discarding any results anyway, so limit data transfer to a minimum

} else if (!usePortal) {

rows = maxRows; // Not using a portal -- fetchSize is irrelevant

} else if (maxRows != 0 && fetchSize > maxRows) {

// fetchSize > maxRows, use maxRows (nb: fetchSize cannot be 0 if usePortal == true)

rows = maxRows;

} else {

rows = fetchSize; // maxRows > fetchSize

}

rows参数对maxRows和fetchSize两个取最小值,最后调用sendExecute

private void sendExecute(SimpleQuery query, Portal portal, int limit) throws IOException {

//

// Send Execute.

//

if (logger.logDebug()) {

logger.debug(" FE=> Execute(portal=" + portal + ",limit=" + limit + ")");

}

byte[] encodedPortalName = (portal == null ? null : portal.getEncodedPortalName());

int encodedSize = (encodedPortalName == null ? 0 : encodedPortalName.length);

// Total size = 4 (size field) + 1 + N (source portal) + 4 (max rows)

pgStream.sendChar('E'); // Execute

pgStream.sendInteger4(4 + 1 + encodedSize + 4); // message size

if (encodedPortalName != null) {

pgStream.send(encodedPortalName); // portal name

}

pgStream.sendChar(0); // portal name terminator

pgStream.sendInteger4(limit); // row limit

pendingExecuteQueue.add(new ExecuteRequest(query, portal, false));

}

从sendExecute的方法参数命名可以看到rows就是limit参数。

PgResultSet.next

postgresql-9.4.1212.jre7-sources.jar!/org/postgresql/jdbc/PgResultSet.java

public boolean next() throws SQLException {

checkClosed();

if (onInsertRow) {

throw new PSQLException(GT.tr("Can''t use relative move methods while on the insert row."),

PSQLState.INVALID_CURSOR_STATE);

}

if (current_row + 1 >= rows.size()) {

if (cursor == null || (maxRows > 0 && row_offset + rows.size() >= maxRows)) {

current_row = rows.size();

this_row = null;

rowBuffer = null;

return false; // End of the resultset.

}

// Ask for some more data.

row_offset += rows.size(); // We are discarding some data.

int fetchRows = fetchSize;

if (maxRows != 0) {

if (fetchRows == 0 || row_offset + fetchRows > maxRows) {

// Fetch would exceed maxRows, limit it.

fetchRows = maxRows - row_offset;

}

}

// Execute the fetch and update this resultset.

connection.getQueryExecutor().fetch(cursor, new CursorResultHandler(), fetchRows);

current_row = 0;

// Test the new rows array.

if (rows.isEmpty()) {

this_row = null;

rowBuffer = null;

return false;

}

} else {

current_row++;

}

initRowBuffer();

return true;

}

可以看到next方法里头也会根据maxRows参数限制fetchRows值,这里的row_offset是值下一批数据第一个元素在整个查询方法结果集中的下标位置。如果fetchSize+row_offset大于了maxRows,则表示下一批拉取的数据如果按fetchSize去拉取,则总拉取数据量会超过maxRows,因此需要修正fetchRows参数,保证总共拉取的数据不超过maxRows

小结

同时开启fetchSize和maxRows参数时,取最小作为limit来executeQuery

maxRows是指executeQuery拉取的数据以及next方法拉取的数据量总和的上限值

对于通用服务而言,设置这个值可以避免因为sql不当导致加载太过数据量最终导致OOM

doc

java的maxrow_聊聊pg jdbc statement的maxRows参数相关推荐

  1. oracle querytimeout,聊聊pg jdbc的queryTimeout及next方法

    序 本文主要介绍一下pg jdbc statement的queryTimeout及resultSet的next方法 实例程序 @Test public void testReadTimeout() t ...

  2. 聊聊tomcat jdbc pool的默认参数及poolSweeper

    序 本文主要研究一下tomcat jdbc pool的默认参数及poolSweeper tomcat jdbc pool 参数默认值 initialSize = 10(默认值) maxActive=1 ...

  3. java面试题3 牛客:下面有关jdbc statement的说法错误的是

    下面有关jdbc statement的说法错误的是? A JDBC提供了Statement.PreparedStatement 和 CallableStatement三种方式来执行查询语句, 其中 S ...

  4. 双表查询java代码_什么是JDBC?Java数据库连接性简介

    JDBC(Java数据库连接性)是Java API,用于管理与数据库的连接,发出查询和命令以及处理从数据库获得的结果集.JDBC在1997年作为JDK 1.1的一部分发布,是为Java持久层开发的首批 ...

  5. java.lang.ClassNotFoundException: com.microsoft.jdbc.sqlserver.SQLServerDriver

    1. 安装:SQL Server 2000 Driver for JDBC Service Pack 3 下载安装JDBC SP3 http://www.microsoft.com/downloads ...

  6. sqlerror.java.1055,at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055)

    错误提示是这样的: java.sql.SQLException at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055) at ...

  7. java操作oracle数据_Java jdbc操作oracle数据库的两种方式

    本文由广州疯狂软件java培训分享: 第一种应该是比较古老的方法了. Windows下采用JDBC-ODBC Bridge连接oracle数据库 1. 安装oracle客户端程序,在tnsnames. ...

  8. 错误信息 Error executing DDL via JDBC Statement 解决办法

    二月 27, 2018 10:34:44 上午 org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl handleExceptio ...

  9. 数据库与Java语言之间的鹊桥——JDBC

    JDBC基本介绍 1. 概念:(Java DataBase Connectivity) Java数据库连接,Java语言操作数据库. JDBC本质:官方(sun公司)定义的一套操作所有关系型数据库的规 ...

最新文章

  1. 连接网络计算机密码错误,局域网电脑连接提示网络错误怎么解决
  2. 项目开发过程中遇到的一些问题和解决办法(逐渐添加)
  3. 视频翻录_将DVD解密并复制到硬盘驱动器而无需翻录
  4. javaweb教务管理系统_基于Java web的教务管理系统
  5. php cdata,PHPcdata处理(详细介绍)_PHP教程
  6. MSSQL游标的原理及示例
  7. React 第九章 表单的使用
  8. 运维学python用不上_运维工程师为什么要学python?
  9. string字符串的查找替换、模式匹配
  10. 系统架构设计-计算机组成与体系结构
  11. PMP考试通关宝典-敏捷专题
  12. 使用Pyecharts进行全国水质TDS地图可视化全过程8:绘制中国地图,使用timeline把多个值放在一个地图上
  13. sm缩写代表什么意思_在嘉庚,这些缩写都是SM意思???
  14. 利用python批量查询企业信息_Python 实现批量查询域名可用性
  15. 阿里P6级别Java程序员月薪多少?阿里认证员工给出答案
  16. 【博客排版】中文文案排版指北(转载)
  17. Mysql中的七种常用查询连接详解
  18. iOS用户行为追踪——无侵入埋点
  19. AES/ECB/PKCS7Padding 加密
  20. Python爬取食品商务网蔬菜价格数据,看看蔬菜最近的价格情况

热门文章

  1. visual studio程序打包发布的方法
  2. vsftpd服务----配置
  3. [转]一个手机游戏的服务器架构
  4. 计算机英语短语与习惯用法词典,清华大学出版社-图书详情-《计算机英语短语与习惯用法词典》...
  5. 5000 字带你快速入门 Apache Kylin
  6. 如何轻松把mysql数据表对齐?!正解在这儿
  7. STM32F103RC 2路ADC 采集显示,水位传感器、MQ2
  8. qq播放器免费的方法
  9. 数据挖掘期末-图注意力模型
  10. 什么是PCB Testpoints