我们在 Java 代码中使用 JDBC 批量更新(Statement - void addBatch(String sql) 和 int[] executeBatch())。该作业应该在表中插入大约 27k 条记录,然后在后续批次中更新大约 18k 条记录。
当我们的工作在早上 6 点运行时,它丢失了几千条记录(我们从数据库审计日志中观察到了这一点)。我们可以从作业日志中看到,正在为所有 18k 记录生成更新语句。我们知道所有更新语句都按顺序添加到批处理中,但是,似乎只有批处理开头的记录丢失了。此外,它不是每天的固定数字 - 一天,它跳过前 4534 条更新语句,另一天跳过前 8853 条记录,另一天,跳过 5648 条记录。
我们最初认为这可能是一个线程问题,但由于被跳过的块并不总是包含相同数量的更新语句,因此已经放弃了这个思考过程。如果我们假设前几千个更新甚至在插入之前就发生了,那么这些更新至少应该显示在数据库审计日志中。然而,这种情况并非如此。
我们认为这是由于内存/堆问题,因为在任何其他时间运行作业都会获取所有 18k 更新语句并且它们已成功执行。我们查看了来自 Oracle 数据库的审计日志,并注意到在早上 6 点运行期间从未在表上执行丢失的更新语句。在任何其他时间,所有更新语句都显示在数据库审计日志中。
这项工作已经成功运行了近 3 年,而这种行为仅在几周前才开始。我们试图查看服务器/环境的任何变化,但没有任何变化。
我们试图查明为什么会发生这种情况,特别是,如果有任何进程占用了过多的 JVM 堆,因此我们的更新语句被覆盖/不被执行。
数据库:Oracle 11g Enterprise Edition Release 11.2.0.3.0 - 64 位 Java:java 版本“1.6.0_51” Java(TM) SE 运行时环境(内部版本 1.6.0_51-b11) Java HotSpot(TM) 服务器 VM(内部版本 20.51-b01 , 混合模式)
void main()
{
DataBuffer dataBuffer;//assume that all the selected data to be updated is stored in this object
List<String> TransformedList = transform(dataBuffer);
int status = bulkDML(TransformedList);
}
public List<String> transform(DataBuffer i_SourceData)
{
//i_SourceData has all the data selected from
//the source table, that has to be updated
List<Row> AllRows = i_SourceData.getAllRows();
List<String> AllColumns = i_SourceData.getColumnNames();
List<String> transformedList = new ArrayList<String>();
for(Row row: AllRows)
{
int index = AllColumns.indexOf("unq_idntfr_col");
String unq_idntfr_val = (String)row.getFieldValues().get(index);
index = AllColumns.indexOf("col1");
String val1 = (String)row.getFieldValues().get(index);
String query = null;
query = "UPDATE TABLE SET col1 = " + val1 + " where unq_idntfr_col=" + unq_idntfr_val;//this query is not the issue either - it is parameterized in our code
transformedList.add(query);
}
return transformedList;
}
public int bulkDML(List<String> i_QueryList)
{
Connection connection = getConnection();
Statement statement = getStatement(connection);
try
{
connection.setAutoCommit(false);
for (String Query: i_QueryList)
{
statement.addBatch(Query);
}
statement.executeBatch();
connection.commit();
}
//handle various exceptions and all of them return -1
//not pertinent to the issue at hand
catch(Exception e)
{
return -1;
}
CloseResources(connection, statement, null);
return 0;
}
任何建议将不胜感激,谢谢。