所以我有一些使用JDBC的java代码,使用准备好的语句将数据插入PostgreSQL数据库,看起来有点像这样:
PreparedStatement statement = // prep statement
for (int value: values) {
statement.setInt(1, value);
statement.addBatch();
}
statement.executeBatch();
问题是,我偶尔会遇到异常java.lang.OutOfMemoryError: Java heap space
。我环顾四周,但我找不到任何东西;如何测试语句是否将耗尽内存以便我可以执行批处理。像这样:
PreparedStatement statement = // prep statement
for (int value: values) {
statement.setInt(1, value);
statement.addBatch();
if (statement.currentSize() + sizeof(int) > statement.mazSize()) {
statement.executeBatch();
}
}
statement.executeBatch();
感谢您的帮助。
答案 0 :(得分:2)
没有可靠的方法可以事先找出实例化是否会失败。
然而,更重要的是:您可能滥用JDBC批处理工具,这可以解决插入多行时网络往返开销的问题。 100以上的批量大小显示收益递减,实际上可能导致减速。
因此,更改您的批处理策略以使用固定批量大小的两位数整数。
答案 1 :(得分:0)
我遇到了与您的代码相似的问题,因为它假定输入数组/列表(values
)的大小最大为三位数-这是在代码级别上由开发人员对其进行编码的一个假设有。
一天,数组/列表接近14k,此代码导致OOM,尽管有一件事我注意到数据已成功提交到DB(其Db2 + Oracle Weblogic设置),几秒钟后OOM,系统出现故障。
要解决此问题,我只是将statement.executeBatch();
设置为预定的固定大小,如下所示,假设固定的批量大小为100,
int counter = 0;
for (int value: values) {
statement.setInt(1, value);
statement.addBatch();
++counter;
if(counter >= 100 ){
statement.executeBatch();
counter =0;
}
}
statement.executeBatch();
我不确定这是否也与驱动程序有关,但是我认为固定的批次数量将因设置的不同而有所不同(我有一个强大的多节点DB2集群,并且Web App是也位于同一数据中心),并且我测试了多种大小,并且1000的速度相当快,没有出现任何问题,但是我减小了大小,因为此代码是从在线UI应用程序中踢出的,因此同一代码可能有多个触发器。
我想这取决于这两者-一个可以保存在内存中的Statement对象的数量以及DB处理一个提交的批处理所花费的时间,因为代码将等待那么长时间。