暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

1345.MySQL JDBC配置FetchSize 预防大数据量加载OOM错误

原创 张鹏 2022-11-22
4988

1345.MySQL JDBC配置FetchSize 预防大数据量加载OOM错误

时间 2019-12-06
标签 mysql jdbc 配置 fetchsize 预防 数据 加载 oom 错误 栏目 MySQL 繁體版
原文 https://my.oschina.net/u/1158288/blog/2413741
JDBC API里在Connection、Statement和ResultSet上都有设置fetchSize的方法,可是默认状况下:MySQL的JDBC驱动都不支持,不管你怎么设fetchSize,ResultSet都会一次性从Server读取所有数据。java
要使得MySQL的JDBC在查询数据加载时是分批加载(而不是一次加载所有),首先MySQL的JDBC驱动版本至少5.0以上,而后有三种方法能够实现:mysql

方法1:sql
stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);

方法2:服务器
调用statement的enableStreamingResults方法,实际上enableStreamingResults()内部封装的就是【方法1】。fetch
stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
((com.mysql.jdbc.Statement)stmt).enableStreamingResults();

方法3:url
在url中设置链接属性useCursorFetch=true (>=5.0版驱动开始支持),statement以TYPE_FORWARD_ONLY打开,再设置fetch size参数,表示采用服务器端游标,每次从服务器取fetch_size条数据。code
url = “jdbc:mysql://localhost:3306/db?useCursorFetch=true”;

stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(x);

如何改变nettimeoutforstreamingresults大小
操作方法如下:
此问题一般是MySQL端数据发送timeout所致。
MySQL中可以设置net_write_timeout这个变量,来调整IO写的时候的超时时间。
由此可知,当客户端长时间不接收数据的时候,就会断开连接。

MySQL JDBC URL各参数详解
通常MySQL连接URL可以设置为:
jdbc:mysql://localhost:3306/test?user=root&password=123456&useUnicode=true&characterEncoding=gbk&autoReconnect=true&failOverReadOnly=false&serverTimezone=UTC&driver=com.mysql.cj.jdbc.Driver
注:test 是数据库名;user 指定登录用户名;password 指定密码。

参数介绍
参数名称 参数说明 缺省值 最低版本要求
user 数据库用户名(用于连接数据库)
password 用户密码(用于连接数据库)
useUnicode 是否使用Unicode字符集,如果参数characterEncoding设置为gb2312或gbk,本参数值必须设置为true false 1.1g
useSSL MySQL在高版本需要指明是否进行SSL连接 在mysql连接字符串url中加入ssl=true或者false即可
characterEncoding 当useUnicode设置为true时,指定字符编码。比如可设置为gb2312或gbk false 1.1g
autoReconnect 当数据库连接异常中断时,是否自动重新连接? false 1.1
autoReconnectForPools 是否使用针对数据库连接池的重连策略 false 3.1.3
failOverReadOnly 自动重连成功后,连接是否设置为只读? true 3.0.12
maxReconnects autoReconnect设置为true时,重试连接的次数 3 1.1
initialTimeout autoReconnect设置为true时,两次重连之间的时间间隔,单位:秒 2 1.1
connectTimeout 和数据库服务器建立socket连接时的超时,单位:毫秒。 0表示永不超时,适用于JDK 1.4及更高版本 0 3.0.1
socketTimeout socket操作(读写)超时,单位:毫秒。 0表示永不超时 0 3.0.1
allowMultiQueries mysql驱动开启批量执行sql的开关 false
serverTimezone 设置时区 例如 serverTimezone=UTC(统一标准世界时间)或serverTimezone=Asia/Shanghai(中国时区)
tinyInt1isBit 如果tinyInt1isBit =true(默认),且tinyInt存储长度为1 ,则转为java.lang.Boolean 。否则转为java.lang.Integer。 true
中文环境中,characterEncoding配置为gbk
出现中文乱码时,解决办法就是:useUnicode=true&characterEncoding=UTF-8
UTC是统一标准世界时间
如果tinyInt1isBit =true(默认),且把数据类型tinyInt存储长度设为1,那么数据库tinyInt类型会自动转成Java的Boolean,否则自动转成Java的Integer。如果希望转成Java的整数型,则将tinyInt1isBit设为false,或者把tinyInt的长度设为大于1,即tinyInt(N), N>1,例如 tinyInt(2)。也就是说,默认情况下,把字段的数据类型定义为tinyInt(1) ,是用来代表Boolean含义的字段,对应的是Java的Boolean类型,如果插入true,数据库会自动保存1,插入false数据库会自动保存0
inyInt1isBit参数名区分大小写,否则不生效
在使用数据库连接池的情况下,最好设置如下两个参数:
autoReconnect=true&failOverReadOnly=false
在xml配置文件中,url中的&符号需要转义成&amp ;。比如在tomcat的server.xml中配置数据库连接池时,MySQL JDBC URL如下:
jdbc:mysql://localhost:3306/test?user=root&password=&useUnicode=true&characterEncoding=gbk
&autoReconnect=true&failOverReadOnly=false

mysql jdbc url具体参数全解

mysql jdbc url具体参数全解。mysql jdbc url具体参数详解。mysql jdbc url具体参数什么意思。

MySQL的 JDBC URL格式:
jdbc:mysql://localhost:3306/easonjim?profileSQL=true

对应中文环境,通常MySQL连接URL可以设置为:
jdbc:mysql://localhost:3306/test?user=root&password=&useUnicode=true&characterEncoding=gbk&autoReconnect=true&failOverReadOnly=false

需要注意的是,在XML配置文件中,URL中的&符号需要转义。比如在Tomcat的server.xml中配置数据库连接池时,MySQL JDBC URL样例如下:
jdbc:mysql://localhost:3306/test?user=root&password=&useUnicode=true&characterEncoding=gbk
&autoReconnect=true&failOverReadOnly=false

具体的参数参考:

参数名称 参数说明 缺省值 最低版本要求
user 数据库用户名,用于连接数据库 无 所有版本
password 用户密码(用于连接数据库) 无 所有版本
useUnicode 是否使用Unicode字符集,如果参数characterEncoding设置为gb2312或gbk,本参数值必须设置为true false 1.1g
characterEncoding 当useUnicode设置为true时,指定字符编码。比如可设置为gb2312或gbk,utf8 false 1.1g
autoReconnect 当数据库连接异常中断时,是否自动重新连接? false 1.1
autoReconnectForPools 是否使用针对数据库连接池的重连策略 false 3.1.3
failOverReadOnly 自动重连成功后,连接是否设置为只读? TRUE 3.0.12
maxReconnects autoReconnect设置为true时,重试连接的次数 3 1.1
initialTimeout autoReconnect设置为true时,两次重连之间的时间间隔,单位:秒 2 1.1
connectTimeout 和数据库服务器建立socket连接时的超时,单位:毫秒。 0表示永不超时,适用于JDK 1.4及更高版本 0 3.0.1
socketTimeoutsocket 操作(读写)超时,单位:毫秒。 0表示永不超时 0 3.0.1
socketFactory 驱动程序用于创建与服务器套接字连接的类的名称。该类必须实现了接口“com.mysql.jdbc.SocketFactory”,并有公共无参量构造函数。 com.mysql.jdbc.StandardSocketFactory 3.0.3
connectTimeout 套接字连接的超时(单位为毫秒),0表示无超时。仅对JDK-1.4或更新版本有效。默认值为“0”。 0 3.0.1
socketTimeout 网络套接字连接的超时(默认值0表示无超时)。 0 3.0.1
useConfigs 在解析URL属性或应用用户指定的属性之前,加载由逗号“,”分隔的配置属性列表。在文档的“配置”部分中解释了这些配置。 3.1.5
interactiveClient 设置CLIENT_INTERACTIVE标志,根据INTERACTIVE_TIMEOUT而不是WAIT_TIMEOUT向MySQL通报超时连接。 false 3.1.0
propertiesTransform com.mysql.jdbc.ConnectionPropertiesTransform的1个实施实例,在尝试连接之前,驱动程序将使用它来更改传递给驱动的URL属性。 3.1.4
useCompression 与服务器进行通信时采用zlib压缩(真/假)? 默认值为“假”。 false 3.0.17
High Availability and Clustering (高可用性和簇集)
autoReconnect 驱动程序是否应尝试再次建立失效的和/或死连接? 如果允许,对于在失效或死连接上发出的查询(属于当前事务),驱动程序将抛出异常,但在新事务的连接上发出下一个查询时,将尝试再连接。不推荐使用该特 性,这是因为,当应用程序不能恰当处理SQLExceptions时,它会造成与会话状态和数据一致性有关的副作用,设计它的目的仅用于下述情况,即,当 你无法配置应用程序来恰当处理因死连接和/或无效连接导致的SQLExceptions时。作为可选方式,可将MySQL服务器变量“wait_timeout”设置为较高的值,而不是默认的8小时。 false 1.1
autoReconnectForPools 使用适合于连接池的再连接策略(默认值为“假”)。 false 3.1.3
failOverReadOnly 在autoReconnect模式下出现故障切换时,是否应将连接设置为“只读”? true 3.0.12
reconnectAtTxEnd 如果将autoReconnect设置为“真”,在每次事务结束后驱动程序是否应尝试再连接? false 3.0.10
roundRobinLoadBalance 启用了autoReconnect而且failoverReadonly为“假”时,是否应按照循环方式挑选要连接的主机? false 3.1.2
queriesBeforeRetryMaster 出现故障切换(使用多主机故障切换)并返回主机之前发出的查询数。无论首先满足了哪个条件,“queriesBeforeRetryMaster”或“secondsBeforeRetryMaster”,均会再次与主机进行连接。默认值为“50”。 50 3.0.2
secondsBeforeRetryMaster 出现故障切换后,在尝试再次连接到主服务器之前,驱动程序应等待的时间? 无论首先满足了哪个条件,“queriesBeforeRetryMaster”或“secondsBeforeRetryMaster”,均会再次与主 机进行连接。单位为秒,默认值为30。 30 3.0.2
enableDeprecatedAutoreconnect 自3.2版开始,自动再连接功能受到冷落,在3.3版中将删除该功能。将该属性设置为“真”可禁止检查配置的特性。 false 3.2.1
Security (安全)
allowMultiQueries 在一条语句中,允许使用“;”来分隔多条查询(真/假,默认值为“假”)。 false 3.1.1
useSSL 与服务器进行通信时使用SSL(真/假),默认值为“假”。 false 3.0.2
requireSSL 要求SSL连接,useSSL=true? 默认值为“假”。 false 3.1.0
allowUrlInLocalInfile 驱动程序在是“LOAD DATA LOCAL INFILE”语句中否允许URL? false 3.1.4
paranoid 采取措施,防止在错误信息中泄漏敏感信息,并可可能时清除保存敏感数据的数据结构? 默认值为“假”。 false 3.0.1
Performance Extensions (性能扩展)
metadataCacheSize 如果将cacheResultSetMetaData设置为“真”,对cacheResultSetMetadata的查询次数(默认值为50)。 50 3.1.1
prepStmtCacheSize 如果允许预处理语句缓冲功能,应缓冲处理多少条预处理语句? 25 3.0.10
prepStmtCacheSqlLimit 如果允许预处理语句缓冲功能,驱动程序将执行解析缓冲处理的最大SQL是什么? 256 3.0.10
maintainTimeStats 驱动程序是否应维持各种内部定时器,以允许空闲时间计算,以及与服务器的连接失败时允许提供更详细的错误消息? 将该属性设置为“假”,对于每次查询,至少能减少两次对System.getCurrentTimeMillis()的调用。 true 3.1.9
blobSendChunkSize 组块,当通过ServerPreparedStatements发送BLOB/CLOB时使用。 1048576 3.1.9
cacheCallableStmts 驱动程序是否应对CallableStatements的解析过程执行缓冲处理。 false 3.1.2
cachePrepStmts 驱动程序是否应对客户端预处理语句的PreparedStatements的解析过程执行缓冲处理,是否应检查服务器端预处理语句的适用性以及服务器端预处理语句本身? false 3.0.10
cacheResultSetMetadata 驱动程序是否应对用于Statements和PreparedStatements的ResultSetMetaData执行缓冲处理? 要求 JDK-1.4+,真/假,默认为“假”。 false 3.1.1
cacheServerConfiguration 驱动程序是否应根据每条URL对“HOW VARIABLES”和“SHOW COLLATION”的结果执行缓冲处理? false 3.1.5
dontTrackOpenResources JDBC规范要求驱动程序自动跟踪和关闭资源,但是,如果你的应用程序不能明确调用作用在语句或结果集上的close(),可能会导致内存泄漏。将该属性设置为“真”,可放宽该限制,对于某些应用程序,会提供更高的内存效率。 false 3.1.7
dynamicCalendars 需要时,驱动程序是否应检索默认日历,或根据连接/会话对其进行缓冲处理? false 3.1.5
elideSetAutoCommits 如果使用MySQL-4.1或更高版本,当服务器的状态与Connection.setAutoCommit(boolean)请求的状态不匹配时,驱动程序是否仅应发出“set autocommit=n”查询? false 3.1.3
holdResultsOpenOverStatementClose 驱动程序是否应按照JDBC规范的要求关闭Statement.close()上的结果集? false 3.1.7
locatorFetchBufferSize 如果将“emulateLocators”配置为“真”,当获取关于getBinaryInputStream的BLOB数据时,缓冲区的大小应是多少? 1048576 3.2.1
useFastIntParsing 是否使用内部“String->Integer”转换子程序来避免创建过多对象? true 3.1.4
useLocalSessionState 驱动程序是否应引用autocommit的内部值,以及由Connection.setAutoCommit()和Connection.setTransactionIsolation()设置的事务隔离,而不是查询数据库? false 3.1.7
useNewIO 驱动程序是否应将java.nio.* interfaces用于网络通信(真/假),默认为“假”。 false 3.1.0
useReadAheadInput 从服务器读取数据时,是否使用较新的、优化的非成组缓冲输入流? true 3.1.5
Debuging/Profiling (调试/ 仿形)
logger 实现了com.mysql.jdbc.log.Log的类的名称,com.mysql.jdbc.log.Log用于记录消息(默认为“com.mysql.jdbc.log.StandardLogger”,它会将日志记录到STDERR)。 com.mysql.jdbc.log.StandardLogger 3.1.1
profileSQL 跟踪查询以及它们对已配制记录器的执行/获取次数(真/假),默认为“假”。 false 3.1.0
reportMetricsIntervalMillis 如果允许“gatherPerfMetrics”,记录它们的频率是多少(单位毫秒)? 30000 3.1.2
maxQuerySizeToLog 调试或仿形时,控制将记录的查询的最大长度/大小。 2048 3.1.3
packetDebugBufferSize 当“enablePacketDebug”为“真”时,需要保留的最大信息包数目。 20 3.1.3
slowQueryThresholdMillis 如果允许“logSlowQueries”,在将查询记录为“慢”之前的查询时间是多少(毫秒)? 2000 3.1.2
useUsageAdvisor 驱动程序是否应发出“使用情况”警告,就DBC和MySQL Connector/J的恰当和高效使用给出建议(真/假,默认为“假”)? false 3.1.1
autoGenerateTestcaseScript 驱动程序是否应将正在执行的SQL(包括服务器端预处理语句)转储到STDERR? false 3.1.9
dumpQueriesOnException 驱动程序是否应将发送至服务器的查询内容转储到SQLExceptions中? false 3.1.3
enablePacketDebug 允许时,将保留“packetDebugBufferSize”信息包的环形缓冲区,并当在驱动程序代码的关键区域抛出异常时进行转储。 false 3.1.3
explainSlowQueries 如果允许了“logSlowQueries”,驱动程序是否应在服务器上自动发出“EXPLAIN”,并以WARN级别将结果发送给配置好的日志? false 3.1.2
logSlowQueries 是否要记录时间长于“slowQueryThresholdMillis”的查询? false 3.1.2
traceProtocol 是否应记录跟踪级网络协议? false 3.1.2
Miscellaneous (其他)
useUnicode 处理字符串时,驱动程序是否应使用Unicode字符编码? 仅应在驱动程序无法确定字符集映射,或你正在强制驱动程序使用MySQL不是固有支持的字符集时(如UTF-8)才应使用。真/假,默认为“真”。 false 1.1g
characterEncoding 如果“useUnicode”被设置为“真”,处理字符串时,驱动程序应使用什么字符编码? 默认为“autodetect”。 1.1g
characterSetResults 字符集,用于通知服务器以何种字符集返回结果。 3.0.13
connectionCollation 如果设置了它,将通知服务器通过“set collation_connection”使用该校对。 3.0.13
sessionVariables 以逗号隔开的“名称/值”对列表,当驱动程序建立了连接后,以“SET SESSION …”的方式将其发送给服务器。 3.1.8
allowNanAndInf 驱动程序是否应在PreparedStatement.setDouble()中允许NaN或+/- INF值? false 3.1.5
autoDeserialize 驱动程序是否应自动检测并串并转换保存在BLOB字段中的对象? false 3.1.5
capitalizeTypeNames 是否将DatabaseMetaData中的类型名转换为大写? 通常仅在使用WebObjects时有用,真/假。默认为“假”。 false 2.0.7
clobberStreamingResults 这会使“流式”结果集被自动关闭,如果在所有数据尚未从服务器中读取完之前,执行了另一查询,正在从服务器流出的任何未完成数据均将丢失。 false 3.0.9
continueBatchOnError 如果一条语句失败,驱动程序是否应继续处理批命令? JDBC规范允许任何一种方式(默认为“真”)。 true 3.0.3
createDatabaseIfNotExist 如果不存在,创建URL中给定的数据库。假定用户具有创建数据库的权限。 false 3.1.9
emptyStringsConvertToZero 驱动程序是否应允许从空字符串字段到数值“0”的转换? true 3.1.8
emulateLocators N/A false 3.1.0
emulateUnsupportedPstmts 驱动程序是否应检测不被服务器支持的预处理语句,并用客户端模拟版替换它们? true 3.1.7
ignoreNonTxTables 是否忽略关于回退的非事务表? 默认值为“假”。 false 3.0.9
jdbcCompliantTruncation 连接到支持告警的服务器时(MySQL 4.1.0和更高版本),当按照JDBC的要求截短数据时,驱动程序是否应抛出java.sql.DataTruncation异常? true 3.1.2
maxRows 返回的最大行数(0,默认值表示返回所有行)。 -1 all versions
noDatetimeStringSync 不保证ResultSet.getDatetimeType().toString().equals(ResultSet.getString()。 false 3.1.7
nullCatalogMeansCurrent 当DatabaseMetadataMethods请求“目录”参数时,值“Null”是否意味着使用当前目录? 它不兼容JDBC,但符合驱动程序早期版本的传统行为。 true 3.1.8
nullNamePatternMatchesAll 接受*pattern参数的DatabaseMetaData方法是否应将null按对待“%”的相同方式处理(不兼容JDBC,但驱动程序的早期版本能接受与规范的这类偏离)。 true 3.1.8
pedantic 严格遵守JDBC规范。 false 3.0.0
relaxAutoCommit 如果驱动程序所连接的MySQL服务器的版本不支持事务,仍允许调用commit()、rollback()和setAutoCommit()?真/假,默认为“假”。 false 2.0.13
retainStatementAfterResultSetClose 调用ResultSet.close()后,驱动程序是否应将语句引用保存在结果集中? 在JDBC-4.0后,与JDBC不兼容。 false 3.1.11
rollbackOnPooledClose 当连接池中的逻辑连接关闭时,驱动程序是否应发出rollback()? true 3.0.15
runningCTS13 允许在Sun与JDBC兼容的testsuite 1.3版中处理缺陷。 false 3.1.7
serverTimezone 覆盖时区的检测/映射。当服务器的时区为映射到Java时区时使用。 3.0.2
strictFloatingPoint 仅在兼容性测试的早期版本中使用。 false 3.0.0
strictUpdates 驱动程序是否应对可更新结果集进行严格检查(选择所有的主键)?真/假,默认为“真”。 true 3.0.4
tinyInt1isBit 驱动程序是否应将数据类型TINYINT(1)当作BIT类型对待?创建表时,服务器会执行BIT -> TINYINT(1)操作。 true 3.0.16
transformedBitIsBoolean 如果驱动程序将TINYINT(1)转换为不同的类型,为了与MySQL-5.0兼容,驱动程序是否应使用BOOLEAN取代BIT?这是因为MySQL-5.0具有BIT类型。 false 3.1.9
ultraDevHack 由于UltraDev已损坏,并为所有语句发出了prepareCall(),需要时,是否要为prepareCall()创建PreparedStatements? false 2.0.3
useHostsInPrivileges 在DatabaseMetaData.getColumn/TablePrivileges()中为用户添加“@hostname”。真/假,默认为“真”。 true 3.0.2
useOldUTF8Behavior 与4.0和更早版本的服务器进行通信时,使用UTF-8。 false 3.1.6
useOnlyServerErrorMessages 对服务器返回的错误消息,不事先设定“标准的”SQLState错误消息。 true 3.0.15
useServerPrepStmts 如果服务器支持,是否使用服务器端预处理语句? 默认值为“真”。 true 3.1.0
useSqlStateCodes 使用SQL标准状态码取代“传统的”X/Open/SQL状态码,真/假,默认为“真”。 true 3.1.3
useStreamLengthsInPrepStmts 是否采用PreparedStatement/ResultSet.setXXXStream()方法调用中的流长度参数?真/假,默认为“真”。 true 3.0.2
useTimezone 是否在客户端和服务器时区间转换时间/日期类型(真/假,默认为“假”)? false 3.0.2
useUnbufferedInput 不使用BufferedInputStream来从服务器读取数据。 true 3.0.11
yearIsDateType JDBC驱动程序是否应将MySQL类型“YEAR”当作java.sql.Date或SHORT对待? true 3.1.9
zeroDateTimeBehavior 当驱动程序遇到全由0组成的DATETIME值时,应出现什么?MySQL使用它来表示无效日期。有效值是“exception”、“round”和“convertToNull”。 exception 3.1.4
原版手册参考地址如下:https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-configuration-properties.html。

文章知识点与官方知识档案匹配,可进一步学习相关知识
————————————————
版权声明:本文为CSDN博主「小仙饭」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wfanking/article/details/95504879

正确使用MySQL JDBC setFetchSize
MYSQL JDBC快速查询响应的方法,快速返回机制的实现
一直很纠结,Oracle的快速返回机制,虽然结果集很多,可是它能很快的显示第一个结果,虽然通过MYSQl的客户端可以做到,但是通过JDBC却不行。
今天用了1个多小时,终于搞定此问题,希望对广大Java朋友在处理数据库时有个参考。
来由:
通过命令行客户端加上-q参数,可以极快的响应一个查询。
比如结果集为几千万的select * from t1,完整结果集需要20秒,通过-q参数显示第一行只需要不到1秒。
但通过jdbc进行查询,却不可以实现如上的效果,无论怎么调整URL参数,也不行。

过程:
查看了-q参数的解释,如下:
If you have problems due to insufficient memory for large result sets,
use the --quick option. This forces mysql to retrieve results
from the server a row at a time rather than retrieving the entire result set
and buffering it in memory before displaying it. This is done by returning
the result set using the mysql_use_result() C API function in the client/server
library rather than mysql_store_result().

可见,实现快速响应。

查看 mysql_use_result() 函数,这个是C的API,如果通过C开发,可以用这个函数。

那么JAVA呢?

查找标准JDBC规范里面有关函数,没有任何收获。 setFetchSize()看上去有效,可在实际测试里,无任何性能提升。

搜索 JDBC mysql_use_result, 有了意外的收获。

在MYSQL的JDBC,com.mysql.jdbc.Statement 这个接口里发现了如下的内容:
 abstract public  void disableStreamingResults() throws SQLException

Resets this statements fetch size and result set type to the values they 
had before enableStreamingResults() was called.

abstract public void enableStreamingResults() throws SQLException

Workaround for containers that 'check' for sane values of Statement.setFetchSize() 
so that applications can use the Java variant of libmysql's mysql_use_result() behavior. 

原来MySQL提供了自己的一个快速响应的实现。调整测试代码

  stmt = (com.mysql.jdbc.Statement) con.createStatement();
  stmt.setFetchSize(1);
    //按行读取
    // 打开流方式返回机制
    stmt.enableStreamingResults();
    
    我期待的效果出现了。第一行数据被快速的现实出来,时间不到1秒中。

结论:
MySQL在自己的JDBC驱动里提供了特有的功能,来实现查询的快速响应,
特别是结果集非常大或者时间较长,而用户非常想尽快看到第一条结果时特别有效。
from:http://blog.csdn.net/java2000_net/article/details/6869752
正确使用MySQL JDBC setFetchSize()方法解决JDBC处理大结果集 java.lang.OutOfMemoryError: Java heap space
昨天在项目中需要对日志的查询结果进行导出功能。
日志导出功能的实现是这样的,输入查询条件,然后对查询结果进行导出。由于日志数据量比较大。多的时候,有上亿条记录。
之前的解决方案都是多次查询,然后使用limit 限制每次查询的条数。然后导出。这样的结果是效率比较低效。
那么能不能一次查询就把所有结果倒出来了?于是我就使用一次查询,不使用limit分页。结果出现 java.lang.OutOfMemoryError: Java heap space问题。
看来是DB服务器端将一次将查询到的结果集全部发送到Java端保存在内存中。由于结果集比较大,所以出现OOM问题。
首先我想到的是游标功能。那么是不是可以使用游标,一次从服务器端慢慢的取呢?上网查询了一下,大家都说MySQL不支持游标功能等等。
后来就去看JDBC代码。找到了setFetchSize()方法,结果设置以后,却不能生效,还是出现OOM问题。
我的设置如下
[java] view plaincopy

ps=conn.con.prepareStatement(“select * from bigTable”);
ps.setFetchSize(1000);

后来老大在MySQL看到了这样的方法:
[java] view plaincopy

ps = (PreparedStatement) con.prepareStatement(“select * from bigTable”,
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
ps.setFetchSize(Integer.MIN_VALUE);
ps.setFetchDirection(ResultSet.FETCH_REVERSE);
对此解释是:MySQL JDBC默认客户端数据接收方式为如下:
默认为从服务器一次取出所有数据放在客户端内存中,fetch size参数不起作用,当一条SQL返回数据量较大时可能会出现JVM OOM。
要一条SQL从服务器读取大量数据,不发生JVM OOM,可以采用以下方法之一:
1、当statement设置以下属性时,采用的是流数据接收方式,每次只从服务器接收部份数据,直到所有数据处理完毕,不会发生JVM OOM。
setResultSetType(ResultSet.TYPE_FORWARD_ONLY);
setFetchSize(Integer.MIN_VALUE);
2、调用statement的enableStreamingResults方法,实际上enableStreamingResults方法内部封装的就是第1种方式。
3、设置连接属性useCursorFetch=true (5.0版驱动开始支持),statement以TYPE_FORWARD_ONLY打开,再设置fetch size参数,表示采用服务器端游标,每次从服务器取fetch_size条数据。
设置以后,果然可以解决我的问题。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论