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