PreparedStatement executeUpdate()更新错误记录

时间:2014-05-09 10:12:12

标签: java oracle jdbc prepared-statement

我使用的是Oracle数据库,有一段时间后我收到以下异常:

java.sql.SQLException: ORA-01000: maximum open cursors exceeded

我分析了我的代码,我似乎关闭了所有的ResultSet。这种例外有时只会发生。由于这个错误,我决定稍微改变我的代码。以下是代码:

public class Audit {

    private Connection connection;
    private PreparedStatement insertAuditPreparedStatementSent;
    private static int counter;
    private static int JDBC_COUNTER;

    public Audit() throws Exception {
        connection = DriverManager.getConnection("url", "username", "password");
    }

public int insertAudit(String message, java.util.Date sent) throws Exception {
     PreparedStatment preparedStatement = prepareStatement(new String("INSERT INTO Audit (message, sent) VALUES (?, ?)");
     if(JDBC_COUNTER == 0) {
            // this is required to be executed so that ORA-08002 SQLException is not thrown
            connection.createStatement().executeQuery(new String("SELECT AUDIT_SEQUENCE.NEXTVAL FROM DUAL"));
        }
     ResultSet resultSet = connection.createStatement().executeQuery(new String("SELECT AUDIT_SEQUENCE.CURRVAL FROM DUAL"));
     resultSet.next();
     primaryKey = resultSet.getInt(new String("CURRVAL"));
     resultSet.close();
     return primaryKey;
}

public void executeUpdateAudit(int id, java.util.Date sent) throws Exception {
    if(updateAuditPreparedStatement == null) {
         updateAuditPreparedStatement = connection.prepareStatement(new String("UPDATE AUDIT SET SENT = ? WHERE AUDIT_ID = " + id));
    }
    updateAuditPreparedStatement.setTimestamp(1, new java.sql.Timestamp(sent.getDate());
    int i = updateAuditPreparedStatement.executeUpdate();
    connection.commit();   
}

public static void main(String[] args) throws Exception {
     Audit audit = new Audit();
     int primaryKey = audit.insertAudit("message", new java.util.Date());
     audit.executeUpdateAudit(primaryKey, new java.util.Date());
     int primaryKey2 = audit.insertAudit("message2", new java.util.Date());
     audit.executeUpdateAudit(primaryKey2, new java.util.Date());  
}
}

当插入记录2并更新记录2时,只有updateAuditPreparedStatement.executeUpdate()返回1,但数据库更新第一条记录而不是第二条记录。

更改代码的原因是因为我相信PreparedStatement每次都会创建一个新游标。所以,我希望insertAuditPreparedStatementSent在没有关闭的情况下存在于许多插入中。我尝试过insertAuditPreparedStatementSent.clearBatch()insertAuditPreparedStatementSent.clearParameters()

我不确定为什么它会更新记录2的primaryKey上的记录1. SQL很好。

有什么想法吗?

3 个答案:

答案 0 :(得分:1)

你没有关闭这个:

if(JDBC_COUNTER == 0) {
    // this is required to be executed so that ORA-08002 SQLException is not thrown
    connection.createStatement().executeQuery(new String("SELECT AUDIT_SEQUENCE.NEXTVAL FROM DUAL"));
}

还需要关闭准备好的语句,并且在所有这些方法中都缺少try/catch/finally以防止资源泄漏。我强烈反对直接使用JDBC,因为它很难使用。

答案 1 :(得分:1)

executeUpdateAudit中,您使用看到的第一个ID准备语句一次:

if(updateAuditPreparedStatement == null) {
     updateAuditPreparedStatement = connection.prepareStatement(
         new String("UPDATE AUDIT SET SENT = ? WHERE AUDIT_ID = " + id));
}
updateAuditPreparedStatement.setTimestamp(1,
  new java.sql.Timestamp(sent.getDate());

在第二次调用中,第一次调用的ID仍然被使用,因为它在SQL中实际上是硬编码的。

你也应该使用ID的参数:

if(updateAuditPreparedStatement == null) {
     updateAuditPreparedStatement = connection.prepareStatement(
         new String("UPDATE AUDIT SET SENT = ? WHERE AUDIT_ID = ?"));
}
updateAuditPreparedStatement.setTimestamp(1,
    new java.sql.Timestamp(sent.getDate());
updateAuditPreparedStatement.setInt(2, id);

不确定为什么你在任何地方明确地使用new String;它会更简单:

if(updateAuditPreparedStatement == null) {
     updateAuditPreparedStatement = connection.prepareStatement(
         "UPDATE AUDIT SET SENT = ? WHERE AUDIT_ID = ?");
}
updateAuditPreparedStatement.setTimestamp(1,
    new java.sql.Timestamp(sent.getDate());
updateAuditPreparedStatement.setInt(2, id);

这与你的ORA-01000无关,但这似乎是这个问题的主要内容 - 你不应该同时问两件事,特别是如果他们没有直接相关...... < / p>

答案 2 :(得分:-1)

请检查oracle参数

OPEN_CURSORS

您可以在企业管理器中找到它,也可以执行以下SQL:

select * from v$parameter a
where a.NAME = 'open_cursors';

如果此参数非常低(例如&lt; 300)并且您有许多进程/用户同时工作,则可能发生此错误。