Java 和 SQLite:抛出 ResultSet 已关闭但仍在继续

Posted

技术标签:

【中文标题】Java 和 SQLite:抛出 ResultSet 已关闭但仍在继续【英文标题】:Java and SQLite: Throwing ResultSet closed but proceeding 【发布时间】: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 SQLite 3 - JDBC driver throws "ResultsSet Closed" exception on empty resultset的可能重复 【参考方案1】:

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

有关如何使用 JDBC 的更完整描述,请查看 this answer 或 JDBC 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!

以上是关于Java 和 SQLite:抛出 ResultSet 已关闭但仍在继续的主要内容,如果未能解决你的问题,请参考以下文章

“SQLite.SQLiteConnection”的类型初始化器抛出异常

如何使用 JDBC 访问 Tomcat 中的 SQLite 数据库?抛出 UnsatisfiedLinkError

ant sql 任务使用 org.sqlite.JDBC 驱动程序抛出“没有可用的 ResultSet”

FileNotFoundException SQLite 数据库 Android

Android WebView 抛出 SQLiteException

java连接操作数据库的步骤