3

我在数百万条记录上使用批量更新准备语句,但在执行 >400k 记录后最终在运行时遇到以下错误。

java.sql.SQLException: ORA-01000: 超出最大打开游标

不知道是不是下面代码造成的

try{    
conn = ConnectionManager.getConnection();
// turn off autocommit
conn.setAutoCommit(false);

PreparedStatement stmt = conn.prepareStatement(query);

//for each of the records to be updated
for(int k=0;k<objects.length;k++) { 

    stmt.setString(1, objects[k].getValueA());
    stmt.setString(2, objects[k].getValueB());

    stmt.addBatch();

    //running batch execute on every 10000 records
    if(k%10000 == 0 || k == objects.length-1) {
        // submit the batch for execution
        int[] updateCounts = stmt.executeBatch();

        conn.commit();

        if(k < objects.length-1)
        {
            stmt.close();
            stmt = conn.prepareStatement(query);
        }
    }
}
}catch( Exception e ) {
    e.printStackTrace();
}finally {
    if(conn!=null){
        conn.close();
    }
}

从而在提交连接后关闭 PreparedStatement 并用新的 PreparedStatement 替换。我不确定是否重复提交同一连接可能会导致此问题。

任何人都可以提出问题的解决方案或建议更好的架构来处理准备好的语句的批量更新。

P/S:错误行其实是指向delete语句执行的,但我不认为这是根本原因,因为之前批量更新准备语句代码添加之前不存在这个问题。

try {
    if ( hasData ) {
        conn = ConnectionManager.getConnection();
        CommonStore.deleteRecords( conn, queryStr ); //the error point to this line
        hasData = false;
    }
}catch( Exception e ) {
    e.printStackTrace();
}finally {
    if(conn!=null){
        conn.close();
    }
}

感谢您的任何建议

4

1 回答 1

0

我观察到的一件事是:

if(k < objects.length-1)
{
    stmt.close();
    stmt = conn.prepareStatement(query);
}

而不是closing你的stmt对象,我会建议重用它。这只是可以避免的开销。

我认为关闭和重新打开相同的PreparedStatement. 另外,你可以考虑打电话PreparedStatement.clearParameters()addBatch()

于 2012-08-27T04:38:43.000 回答