【发布时间】:2019-02-04 09:57:06
【问题描述】:
从表中选择后尝试写入表时,我收到错误代码 SQLITE_BUSY。 select 语句和结果在我插入之前已正确关闭。
如果我要删除选择部分,则插入工作正常。这就是我没有得到的。根据文档SQLITE_BUSY 应该意味着不同的进程或连接(这里绝对不是这种情况)正在阻塞数据库。
没有运行 SQLite 管理器。 jdbcConn 也是我拥有的与数据库的唯一连接。也没有并行运行的线程。
这是我的代码:
try {
if(!jdbcConn.isClosed()) {
ArrayList<String> variablesToAdd = new ArrayList<String>();
String sql = "SELECT * FROM VARIABLES WHERE Name = ?";
try (PreparedStatement stmt = jdbcConn.prepareStatement(sql)) {
for(InVariable variable : this.variables.values()) {
stmt.setString(1, variable.getName());
try(ResultSet rs = stmt.executeQuery()) {
if(!rs.next()) {
variablesToAdd.add(variable.getName());
}
}
}
}
if(variablesToAdd.size() > 0) {
String sqlInsert = "INSERT INTO VARIABLES(Name, Var_Value) VALUES(?, '')";
try(PreparedStatement stmtInsert = jdbcConn.prepareStatement(sqlInsert)) {
for(String name : variablesToAdd) {
stmtInsert.setString(1, name);
int affectedRows = stmtInsert.executeUpdate();
if(affectedRows == 0) {
LogManager.getLogger().error("Error while trying to add missing database variable '" + name + "'.");
}
}
}
jdbcConn.commit();
}
}
}
catch(Exception e) {
LogManager.getLogger().error("Error creating potentially missing database variables.", e);
}
这会在 int affectedRows = stmtInsert.executeUpdate(); 上崩溃。现在,如果我删除第一个块(并手动将一个值添加到 variablesToAdd 列表中),该值将很好地插入到数据库中。
我错过了什么吗?我没有正确关闭 ResultSet 和 PreparedStatement 吗?也许我看得太久了,我对自己的错误视而不见。
编辑:在单独的线程中执行选择也可以解决问题。但这不可能是解决方案。关闭之前的语句后,我是否试图太快地插入数据库?
Edit2:我遇到了一个 busy_timeout,它承诺让更新/查询在返回 SQLITE_BUSY 之前等待指定的时间。我尝试像这样设置繁忙超时:
if(jdbcConn.prepareStatement("PRAGMA busy_timeout = 30000").execute()) {
jdbcConn.commit();
}
executeUpdate() 函数仍会立即返回 SQLITE_BUSY。
【问题讨论】:
-
你写了 select 语句和结果在我插入之前正确关闭。,但你从不调用
stmt.close()。所以,你的陈述没有正确结束。 -
由于我使用了try-with-resource,它应该正确关闭:docs.oracle.com/javase/tutorial/essential/exceptions/… 但我可能会尝试传统的try-finally-close,看看它是否有所作为。
-
啊,现在我明白了。不,理论上,隐式关闭应该适用于 JDBC。但是,这仍然会消除一个潜在的错误。
-
@M.Folte - 我似乎无法使用 sqlite-jdbc-3.25.2.jar 重现您的问题。你运行的是什么版本?
-
@Gord Thompson - 正在运行 3.19.3。不知道为什么我没有更新的想法。不幸的是,即使在 3.25.2 上,问题仍然存在。