【问题标题】:Java and SQLite: Throwing ResultSet closed but proceedingJava 和 SQLite:抛出 ResultSet 已关闭但仍在继续
【发布时间】:2014-04-01 17:59:25
【问题描述】:

我遇到了以下问题:我正在尝试使用以下代码将数据(在本例中为用户名)插入到表中:

void AddNewUser(String name, Connection conn){

    if(ret == null){
        ret = new DB_Retriever(conn);
    }

    if(!ret.UserExists(name, conn)){
        try{
            Statement stm = conn.createStatement();
            stm.executeUpdate(DB_OperationalData.insert_new_user[0][0] + name + DB_OperationalData.insert_new_user[0][1]);
            stm.executeUpdate(DB_OperationalData.insert_new_user[1][0] + name + DB_OperationalData.insert_new_user[1][1]);
            stm.close();
        }
        catch(SQLException e){
            e.printStackTrace();
        }
    }
}

顺便说一句:我在 catch 子句中放什么绝对无关紧要,我放在那里的任何东西都不会被执行。为了说明一切,这里是 DB_OperationalData.insert_new_user 字符串数组的内容:

public static final String[][] insert_new_user = {
    {"INSERT INTO User (Username, Status) VALUES ('","','IN');"},
    {"INSERT INTO Statistics (Player_ID) SELECT ID FROM User WHERE Username='","';"}};

第二条语句应该复制插入的用户ID,并将其放入Statistics表的Player_ID字段中(表用户ID是一个自动编号的字段)。

我得到的例外是:

Error while processing the query: java.sql.SQLException: ResultSet closed

有趣的是,它可以正常工作并且正确添加了数据,但我根本不希望抛出任何异常。

这是我得到的控制台输出:

This is 'data' Package Testing class
Connection to the database established.
The number of tables existing in the database is: 0
All the queries have been processed successfully
Adding new users: 
Error while processing the query: java.sql.SQLException: ResultSet closed

异常上面的所有行都是我自己的打印输出,所以我知道实际发生了什么。

[编辑]

我已将代码更改为使用 PreparedStatement 而不是普通的 Statement,当前的 try 子句如下所示:

PreparedStatement pstm = conn.prepareStatement(DB_OperationalData.insert_new_user[0]);
pstm.setString(1, name);
pstm.addBatch();
conn.setAutoCommit(false);
pstm.executeBatch();
conn.setAutoCommit(true);
pstm.close();

并且输出是(仍然不管catch子句的内容):

This is 'data' Package Testing class
Connection to the database established.
The number of tables existing in the database is: 0
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
at org.sqlite.PrepStmt.batch(PrepStmt.java:173)
at org.sqlite.PrepStmt.setString(PrepStmt.java:254)
at data.DB_Writer.AddNewUser(DB_Writer.java:28)
at data.DataHandler.AddNewUser(DataHandler.java:94)
at data.Tester.main(Tester.java:18)
All the queries have been processed successfully
Adding new users: 
Error while processing the query: java.sql.SQLException: ResultSet closed

[编辑 2] 关于原始版本,当我删除 stm.close();绝对没有区别,我仍然得到 'ResultSet closed' 异常。

[编辑 3] 以下是调用上述方法的代码:

public void AddNewUser(String username)throws IllegalUsernameException{
    if(username.length()==0 || username.length()>20){
        throw new IllegalUsernameException();
    }
    writer.AddNewUser(username, conn);

}

通过这个类建立与数据库的连接:

class DB_Connection {


public static Connection getConnection(){
    Connection conn = null;

    try{
        Class.forName("org.sqlite.JDBC");
    }
    catch(ClassNotFoundException e){
        log("Error while loading the database driver: " + e);
        return null;
    }
    try{
        conn = DriverManager.getConnection("jdbc:sqlite:database.db");
    }
    catch(SQLException e){
        log("Unable to connect to the database: " + e);
        return null;
    }
    return conn;
}

public static void log(String msg){
    System.out.println(msg);
}

}

正在检查现有用户名的 DB_Retriever 方法:

boolean UserExists(String name, Connection conn){

    String result = "";

    try{
        Statement stm = conn.createStatement();
        ResultSet rs = stm.executeQuery(DB_OperationalData.user_exists[0] + name + DB_OperationalData.user_exists[1]);
        result = rs.getString("Username");
    }
    catch(SQLException e){
        System.out.println("Error while processing the query: " + e);
    }

    if(result.equals(name)){
        return true;
    }

    return false;
}

【问题讨论】:

  • 请添加堆栈跟踪。还要检查抛出异常的确切位置(类和行号)。为了澄清,异常是在空的 catch 块到位的情况下引发的?那么它不能是由您显示的代码引起的。根据定义,catch 块将阻止异常传播。其他可能有助于找到原因的有趣问题:连接是在哪里以及如何创建的?你使用连接池吗? DB_Retriever 在做什么?你为什么不结束声明?请承诺在修复此错误后立即阅读有关 java.sql.PreparedStatement 的内容!
  • catch 块为空时抛出异常,非空时也会抛出异常。连接是在一个单独的类中创建的,我将添加它。 DB_Retriever 只是从数据库中读取数据,不会抛出任何异常。在这种情况下,它会检查给定的用户名是否已经存在于数据库中。更新代码以反映建议。
  • 就目前而言,控制台输出对我们来说毫无用处,因为我们不知道您的代码。输出中引用的异常 cannot 从您发布的 try-catch 块内的代码中抛出。在代码中的其他地方捕获了 SQLException 并打印了 exception.message() 值。找到那个 catch 块并将其更改为至少打印一个堆栈跟踪。然后检查堆栈跟踪中的类和行号。如果您无法弄清楚,请使用触发异常的代码部分更新您的问题。提示:DML 语句不创建结果集。 SELECT 可以。
  • @Pyranja 我确实意识到 DML 语句不应该创建任何结果集,这也是我对这个异常感到困惑的原因。标准的 executeUpdate 方法仅返回一个整数,其中包含已更改的行数。我已经插入了一些 println 语句,结果现在更加有趣:当执行 try 块时,我们最终得到:ResultSet 异常,我的字符串在声明 PreparedStatement 之后直接打印,并分配了插入查询,然后是 ArrayOutOfBoundsException被抛出并且这个异常指向 PrepStmt.java

标签: java sql sqlite exception resultset


【解决方案1】:

Error while processing the query: java.sql.SQLException: ResultSet closed 可以打印到控制台的唯一位置是UserExists(..),除非有其他方法具有类似的 catch 块。确实,ResultSet 在UserExists 中没有正确使用,可能会导致错误。

有关如何使用 JDBC 的更完整描述,请查看 this answerJDBC documentation。现有UserExists 的可能替代方案是:

boolean userExists(String name, Connection conn) {
   PreparedStatement stmt = null;
   try{
      stmt = conn.prepareStatement("SELECT COUNT(Username) FROM User WHERE Username = ?");
      stmt.setString(1, name);
      ResultSet rs = stmt.executeQuery();
      rs.next();  // set cursor to first row
      int count = rs.getInt(1);
      rs.close();
      return count > 0;
   } catch(SQLException e) {
      // propagate error
      throw new RuntimeException(e);
   } finally {
      // clean up resources
      if (stmt != null) {
        try {
           stmt.close();
        } catch (SQLException ignore) {
           log("error on sql clean up", ignore);
        }
      }
   }
}

【讨论】:

  • 非常感谢。我确实意识到它不可能是写入数据库的类,但现在我知道发生了什么。也感谢您向我介绍 Prepared Statement!
猜你喜欢
  • 2017-04-16
  • 1970-01-01
  • 2014-01-17
  • 2014-12-29
  • 2018-08-16
  • 2018-09-17
  • 1970-01-01
  • 2012-04-07
相关资源
最近更新 更多