1

我有一个基于 Play Framework 2.3 (scala) 的简单 Web 应用程序,它目前使用 sqlite3 作为数据库。我有时但并非总是会因将行插入数据库而导致异常:

java.sql.SQLException: statement is not executing
  at org.sqlite.Stmt.checkOpen(Stmt.java:49) ~[sqlite-jdbc-3.7.2.jar:na]
  at org.sqlite.PrepStmt.executeQuery(PrepStmt.java:70) ~[sqlite-jdbc-3.7.2.jar:na]
  ...

问题出现在几个不同的上下文中,都源自 SQL(statement).executeInsert()

例如:

val statementStr = "insert into session_record (condition_id, participant_id, client_timestamp,   server_timestamp) values (%d,'%s',%d,%d)".format(conditionId,participantId,clientTime,serverTime)

DB.withConnection( implicit c => {
  val ps = SQL(statement)
  val pKey = populatedStatement.executeInsert()
  // ...
}

没有抛出异常时,pKey 包含一个带有表的自动递增主键的选项。当抛出异常,数据库的状态表明基本语句执行,如果我将记录的 SQL 语句手动尝试一下,它也可以毫无问题地执行。

不使用“executeInsert”执行的插入语句也可以工作。此时,我可以只使用“.execute()”并单独获取最大主键,但我担心可能会遗漏一些更深层次的问题。

一些配置细节:

在 application.conf 中:

db.default.driver=org.sqlite.JDBC
db.default.url="jdbc:sqlite:database/mySqliteDb.db"

我的 sqlite 版本是 3.7.13 2012-07-17

我使用的 JDBC 驱动程序是“org.xerial”%“sqlite-jdbc”%“3.7.2”(通过 build.sbt)。

4

2 回答 2

1

我今天使用最新的驱动程序遇到了同样的问题,使用 execute() 是我找到的最接近解决方案的方法。

为了完整起见,在 Stmt.java 上为 getGeneratedKeys() 注释:

/**
 * As SQLite's last_insert_rowid() function is DB-specific not statement
 * specific, this function introduces a race condition if the same
 * connection is used by two threads and both insert.
 * @see java.sql.Statement#getGeneratedKeys()
 */

大多数人肯定会确认这是驱动程序中难以修复的错误,由于 SQLite 的设计,这使得 executeInsert() 不是线程安全的。

于 2014-09-12T20:51:20.193 回答
0

首先,最好不要使用格式将参数传递给语句,而是使用 SQL("INSERT ... {aParam}").on('aParam -> value) 或 SQL"INSERT ... $value" (使用异常插值)。然后,如果仍然存在异常,我建议您在普通的独立 Java 测试应用程序中测试连接/语句。

于 2014-07-11T23:10:47.527 回答