2014-05-09 25 views
0

我使用的是Oracle數據庫和一段時間後我收到以下異常:的PreparedStatement的executeUpdate()更新錯誤的記錄

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很好。

任何想法?

回答

-1

請檢查Oracle參數

OPEN_CURSORS

您將在企業管理器或通過執行以下SQL找到這個:

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

如果這個參數是非常低的(如< 300 )並且你有很多進程/用戶在同一時間工作,這個錯誤可能會發生。

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,因爲它很難處理。

+0

我正在關閉我的結果集。看看方法insertAudit()方法。我必須使用JDBC,因爲我的公司不允許JDBC以外的任何其他內容。我想停止java.sql.SQLException:ORA-01000:最大打開遊標超出異常。所以,我決定不關閉PreparedStatement並將其重新用於所有插入。這是一個問題嗎?你能提出另一種解決方案嗎 – user3189663

+1

使用Java 7試用資源可以更加輕鬆地正確處理JDBC資源。 –

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,但是這似乎是這個問題的主旨 - 你真的不應該問兩件事一次,特別是如果他們不直接相關...