在 PreparedStatement 中设置 FetchSize 时 Oracle 驱动程序发生 OutOfMemoryError
Posted
技术标签:
【中文标题】在 PreparedStatement 中设置 FetchSize 时 Oracle 驱动程序发生 OutOfMemoryError【英文标题】:OutOfMemoryError occurred in Oracle driver when setFetchSize in PreparedStatement 【发布时间】:2014-01-16 10:34:19 【问题描述】:我有这段代码,这段代码基本上在PreparedStatement
中设置了限制,以避免加载整个表数据。
PreparedStatement pstmt = null;
ResultSet rs = null;
try
pstmt = con.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
if (getDataSheet().isPagingEnabled())
pstmt.setFetchSize(getDataSheet().getPageSize() + 1);
if (getDataSheet().isDisableTotalRowsCount() && maxRecords >= 0)
if (getDataSheet().isPagingEnabled())
pstmt.setMaxRows(getCurrentPageSize());
else
pstmt.setMaxRows(maxRecords);
//the rest of code.
catch(Exception ex)
//handle exception
此代码适用于所有数据库供应商,除了 Oracle 驱动程序中的一种情况,如果我在 PreparedStatement
中使用 setFetchSize
,并且页面大小超过 20000,驱动程序会抛出 OutOfMemoryError
Caused by: java.lang.OutOfMemoryError: Java heap space
at oracle.jdbc.driver.PhysicalConnection.getCharBuffer(PhysicalConnection.java:7018)
at oracle.jdbc.driver.OracleStatement.prepareAccessors(OracleStatement.java:907)
at oracle.jdbc.driver.T4CTTIdcb.receiveCommon(T4CTTIdcb.java:261)
at oracle.jdbc.driver.T4CTTIdcb.receive(T4CTTIdcb.java:127)
at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:992)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:194)
at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:791)
at oracle.jdbc.driver.T4CPreparedStatement.executeMaybeDescribe(T4CPreparedStatement.java:866)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1186)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3387)
at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3431)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeQuery(OraclePreparedStatementWrapper.java:1203)
知道为什么甲骨文会发生这种情况吗?在数据库级别有什么想法吗? 提前致谢。
【问题讨论】:
为什么要一次性获取 20k 行? fetch size 的用途是获取一批行,对其进行处理,然后再获取另一批——从而限制了到数据库的往返次数。它不是意味着在一个大规模的内存批处理中获取所有行。 【参考方案1】:与您的想法相反,setFetchSize
不限制检索的记录数量,它确定(或提示)驱动程序应预取和缓存多少记录。 mysql 是个例外,它总是预取所有记录,除非您将提取大小设置为Integer.MIN_VALUE
。
驱动程序只是检索太多行,以至于内存耗尽。
【讨论】:
是的,我明白了,我对setFetchSize
有误解,好的,那么这是setFetchSize(Integer.MIN_VALUE)
的最佳做法还是最佳号码?
@JUBA 不,你应该使用一个合理的数字(比如 1 到 500 之间);效果可能因驱动程序和数据库而异(我建议测试它是否真的能提高性能)。 Integer.MIN_VALUE
仅适用于 MySQL!以上是关于在 PreparedStatement 中设置 FetchSize 时 Oracle 驱动程序发生 OutOfMemoryError的主要内容,如果未能解决你的问题,请参考以下文章
带有 IN 子句中参数列表的 PreparedStatement [重复]