Java Prepared语句在错误后保持游标打开

时间:2015-09-30 08:19:42

标签: java oracle

我正在编写一个Java类,通过迭代将数据插入到数据库中。虽然我现在可以插入数据,但我正在努力处理Oracle错误。在这种情况下,我故意通过尝试插入重复的主键来创建主键约束错误(我已使用与我尝试使用Java插入的条目预先加载数据库)

正如所料,我得到了" ORA-00001:唯一约束"。但是,我遇到的问题是,经过300次迭代后,我遇到了一个新的错误:" ORA-01000:超出最大打开游标"

我想问题是每个失败的executeUpdate()都会打开游标。

我通过在错误的捕获上包含close()语句暂时解决了这个问题。但是,我想知道:

  • 失败的executeUpdate()是否应关闭光标?
  • 我有更好的方法可以关闭Exception上的游标吗?
  • 为什么会返回null异常?

我的Java代码:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class TestOracleError {
    private static Connection conn;
    public static void main(String[] args) {
        //Connect
        try {
            conn = DriverManager.getConnection("jdbc:oracle:thin:"+
                    "@XXX.XXX.XXX.XXX:1521:XXXX", "XXXX", "XXXX");
        }
        catch(SQLException e) {
            System.err.println(e.getMessage());
        }

        //Iterate insert
        for(int i=1; i<5000; i++){
            PreparedStatement pstmt=null;
            try {
                //Deliberate error on the SQL (Primary Key Constraint)
                pstmt = conn.prepareStatement("INSERT INTO DUMMY (ID) VALUES "
                        +"('"+i+"')");
                pstmt.executeUpdate();
                pstmt.close();            
            }
            catch(Exception e) {
                System.err.println("DB Error on iteration "+i+": " + 
                        e.getMessage());
                //If I add the following line then I can close the error!
                //try {pstmt.close();} catch (Exception e1) {} 
            }    
        }
    }
}

3 个答案:

答案 0 :(得分:2)

最后使用或尝试使用资源。

try {
        //Deliberate error on the SQL (Primary Key Constraint)
        // Only set the variable in the loop
        pstmt.setInt(1, i);
        pstmt.executeUpdate();

    } catch (Exception e) {
        System.err.println("DB Error on iteration "+i+": " + 
                    e.getMessage());
        //If I add the following line then I can close the error!
        //try {pstmt.close();} catch (Exception e1) {} 
    }    
    finally
    {
        pstmt.close();
    }

try (Connection con = DriverManager.getConnection(myConnectionURL);
             PreparedStatement ps = con.prepareStatement(sql);) {
            ......
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }

答案 1 :(得分:1)

如果需要插入多行,则在循环外部创建预准备语句,并仅设置循环内的值。

// Moved outside
PreparedStatement pstmt=null;

// Using the question mark as a placeholder for a variable
pstmt = conn.prepareStatement("INSERT INTO DUMMY (ID) VALUES (?)");

for (int i = 1; i < 5000; i++) {

    try {
        //Deliberate error on the SQL (Primary Key Constraint)
        // Only set the variable in the loop
        pstmt.setInt(1, i);
        pstmt.executeUpdate();

    } catch (Exception e) {
        System.err.println("DB Error on iteration "+i+": " + 
                    e.getMessage());
        //If I add the following line then I can close the error!
        //try {pstmt.close();} catch (Exception e1) {} 
    }    
}
pstmt.close();  // Moved out of loop

注意:如果发生异常,您的代码不会关闭pstmt。所以声明仍然开放。这可能会产生太多打开游标的问题。

通常,最佳解决方案是关闭finally块中的资源或使用尝试使用资源声明

答案 2 :(得分:0)

  

我想问题是每个失败的executeUpdate()都会保持游标打开。

不,问题是如果发生PreparedStatements,您就不会关闭SQLException

  

失败的executeUpdate()是否应该关闭光标?

没有

  

有没有更好的方法可以关闭Exception上的游标?

关闭PreparedStatement块中的finally,或使用try-with-resources语法。

  

为什么会返回null异常?

它没有。它使用null 消息抛出异常。

您应该调查批次,而不是准备5000 PreparedStatements