我们正在使用JAVA代码中的JDBC Batch Update(语句-Void AddBatch(String sql)和int [] executeBatch())。该作业应该在表中插入约27K记录,然后在随后的批次中更新大约18k记录。
当我们的作业在凌晨6点运行时,它缺少数千个记录(我们从数据库审核日志中观察到了)。从作业日志中,我们可以看到所有18K记录的更新语句正在生成。我们了解到,所有更新语句都会按顺序添加到批处理中,但是,仅从批次开始就没有记录。另外,它不是每天固定的数字 - 有一天,它跳出了第一个4534更新声明,另一天跳出了第一个8853记录,而另一天则跳出了5648记录。
我们最初认为这可能是一个线程问题,但此后已经离开了该思维过程,因为被跳出的块并不总是包含相同数量的更新语句。如果我们假设最初的几千个更新甚至在插入之前就会发生,则更新至少应显示在数据库审核日志中。但是,情况并非如此。
我们认为这是由于内存/堆问题造成的,因为在任何其他时间运行作业都会选择所有18K更新语句,并且成功执行。我们从Oracle数据库中审查了审核日志,并注意到在凌晨6点运行期间,丢失的更新语句从未执行。在其他任何时候,所有更新语句都显示在数据库审核日志中。
这项工作已经成功运行了将近3年,这种行为仅在几周前就开始了。我们试图查看服务器/环境的任何更改,但没有任何兴起。
我们正在尝试指出为什么有任何流程使用过多的JVM堆,因此,我们的更新语句被覆盖/未执行。
。数据库:Oracle 11G企业版版本11.2.0.3.0-64bitJava:Java版本" 1.6.0_51"Java(TM)SE运行时环境(构建1.6.0_51-B11)Java热点(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;
}
任何建议将不胜感激,谢谢。
如果要在同一表上执行多个更新,我建议修改查询以使用binds和准备台面,因为这确实是使用Oracle Database进行真实DML批处理的唯一方法。例如,您的查询将成为:
UPDATE TABLE SET col1=? WHERE unq_idntfr_col=?
,然后将JDBC批处理与相同的准备安排使用。此更改需要您重新审视您的批量方法,以使其以绑定为参数而不是SQL。
。JDBC伪代码将看起来像这样:
PreparedStatement pstmt = connection.prepareCall("UPDATE TABLE SET col1=? WHERE unq_idntfr_col=?");
pstmt.setXXX(1, x);
pstmt.setYYY(2, y);
pstmt.addBatch();
pstmt.setXXX(1, x);
pstmt.setYYY(2, y);
pstmt.addBatch();
pstmt.setXXX(1, x);
pstmt.setYYY(2, y);
pstmt.addBatch();
pstmt.executeBatch();