Java PreparedStatement executeUpdate()更新错误记录
我正在使用Oracle数据库,过了一段时间后,我收到以下异常:Java PreparedStatement executeUpdate()更新错误记录,java,oracle,jdbc,prepared-statement,Java,Oracle,Jdbc,Prepared Statement,我正在使用Oracle数据库,过了一段时间后,我收到以下异常: java.sql.SQLException: ORA-01000: maximum open cursors exceeded 我分析了我的代码,似乎要关闭所有的结果集。这种例外只是偶尔发生。由于这个错误,我决定稍微修改一下代码。代码如下: public class Audit { private Connection connection; private PreparedStatement insertAud
java.sql.SQLException: ORA-01000: maximum open cursors exceeded
我分析了我的代码,似乎要关闭所有的结果集。这种例外只是偶尔发生。由于这个错误,我决定稍微修改一下代码。代码如下:
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每次都会创建一个新的游标。因此,我希望InsertAuditPreparedStatement发送到许多插入中而不关闭。我已经尝试了insertAuditPreparedStatementSent.clearBatch()
和insertAuditPreparedStatementSent.clearParameters()
我不知道它为什么要在记录2的主密钥上更新记录1。SQL很好
有什么想法吗?请检查oracle参数 打开游标 您可以在enterprise manager中或通过执行以下SQL来找到这一点:
select * from v$parameter a
where a.NAME = 'open_cursors';
如果此参数非常低(例如<300),并且有许多进程/用户同时工作,则可能发生此错误。您没有关闭此:
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,因为它很难使用。在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);
不确定为什么在任何地方都显式地使用新字符串
;更简单的是:
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无关,但这似乎是这个问题的主旨-您不应该同时询问两件事,特别是如果它们没有直接关系的话…我正在关闭我的结果集。请查看insertAudit()方法。我必须使用JDBC,因为我的公司不允许除JDBC之外的任何东西。我想停止java.sql.SQLException:ORA-01000:超出最大打开游标数异常。因此,我决定不关闭PreparedStatement并在所有插入中重复使用它。这是个问题吗?您能推荐另一种解决方案吗?使用Java7,可以更轻松地正确处理JDBC资源。