JDBC批处理更新跳过了初始更新语句集



我们正在使用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();

相关内容

  • 没有找到相关文章

最新更新