【问题标题】:Query in Quill crashing at runtime on syntax errorQuill 中的查询在运行时因语法错误而崩溃
【发布时间】:2017-11-25 10:35:23
【问题描述】:

相关sn-ps:

case class Video(
  id: String,
  title: String,
  url: String,
  pictureUrl: String,
  publishedAt: Date,
  channel: String,
  duration: Option[String],
  createdOn: Date
)

“连接”到数据库正在工作,从视频表中选择会返回预期结果。我保存有问题,这个简单的方法:

  def saveToCache(item: Video): Unit = {
    logger.trace(item)
    import ctx._
    val x = quote {
      val lItem = lift(item)
      val fromDb = query[Video].filter(_.id == lItem.id)
      if (fromDb.isEmpty) query[Video].insert(lItem)
      else fromDb.update(lItem)
    }
    logger.trace(x.ast)
    run(x)
  }

在运行时崩溃(缩短):

11:14:06.640 [scala-execution-context-global-84] ERROR io.udash.rpc.AtmosphereService - RPC request handling failed
org.sqlite.SQLiteException: [SQLITE_ERROR] SQL error or missing database (near "CASE": syntax error)
        at org.sqlite.core.DB.newSQLException(DB.java:909) ~[sqlite-jdbc-3.18.0.jar:na]
        at org.sqlite.core.DB.newSQLException(DB.java:921) ~[sqlite-jdbc-3.18.0.jar:na]
        at org.sqlite.core.DB.throwex(DB.java:886) ~[sqlite-jdbc-3.18.0.jar:na]
        at org.sqlite.core.NativeDB.prepare_utf8(Native Method) ~[sqlite-jdbc-3.18.0.jar:na]
        at org.sqlite.core.NativeDB.prepare(NativeDB.java:127) ~[sqlite-jdbc-3.18.0.jar:na]
        at org.sqlite.core.DB.prepare(DB.java:227) ~[sqlite-jdbc-3.18.0.jar:na]
        at org.sqlite.core.CorePreparedStatement.<init>(CorePreparedStatement.java:41) ~[sqlite-jdbc-3.18.0.jar:na]
        at org.sqlite.jdbc3.JDBC3PreparedStatement.<init>(JDBC3PreparedStatement.java:30) ~[sqlite-jdbc-3.18.0.jar:na]
        at org.sqlite.jdbc4.JDBC4PreparedStatement.<init>(JDBC4PreparedStatement.java:19) ~[sqlite-jdbc-3.18.0.jar:na]
        at org.sqlite.jdbc4.JDBC4Connection.prepareStatement(JDBC4Connection.java:48) ~[sqlite-jdbc-3.18.0.jar:na]
        at org.sqlite.jdbc3.JDBC3Connection.prepareStatement(JDBC3Connection.java:263) ~[sqlite-jdbc-3.18.0.jar:na]
        at org.sqlite.jdbc3.JDBC3Connection.prepareStatement(JDBC3Connection.java:235) ~[sqlite-jdbc-3.18.0.jar:na]
        at com.zaxxer.hikari.pool.ProxyConnection.prepareStatement(ProxyConnection.java:317) ~[HikariCP-2.7.2.jar:na]
        at com.zaxxer.hikari.pool.HikariProxyConnection.prepareStatement(HikariProxyConnection.java) ~[HikariCP-2.7.2.jar:na]
        at io.getquill.context.jdbc.JdbcContext.$anonfun$executeAction$1(JdbcContext.scala:98) ~[quill-jdbc_2.12-2.2.0.jar:2.2.0]
        at io.getquill.context.jdbc.JdbcContext.$anonfun$executeAction$1$adapted(JdbcContext.scala:97) ~[quill-jdbc_2.12-2.2.0.jar:2.2.0]
        at io.getquill.context.jdbc.JdbcContext.$anonfun$withConnection$1(JdbcContext.scala:46) ~[quill-jdbc_2.12-2.2.0.jar:2.2.0]
        at scala.Option.getOrElse(Option.scala:121) ~[scala-library-2.12.2.jar:1.0.0-M1]
        at io.getquill.context.jdbc.JdbcContext.withConnection(JdbcContext.scala:44) ~[quill-jdbc_2.12-2.2.0.jar:2.2.0]
        at io.getquill.context.jdbc.JdbcContext.executeAction(JdbcContext.scala:97) ~[quill-jdbc_2.12-2.2.0.jar:2.2.0]

编译期间宏的相关输出:

CASE WHEN NOT EXISTS (SELECT x3.* FROM video x3 WHERE x3.id = ?) THEN INSERT INTO video (id,title,url,picture_url,published_at,channel,duration,created_on) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ELSE UPDATE video SET id = ?, title = ?, url = ?, picture_url = ?, published_at = ?, channel = ?, duration = ?, created_on = ? WHERE id = ? END

我想启用查询记录,但我不知道该怎么做(Quill 文档只说了一些关于 SLF4J 的信息,这对我来说是无用的信息 - 我没有看到任何日志,我不知道该怎么做在 SLF4J 文档中搜索)。

到目前为止,我对 Quill 感到非常失望——它第一次在使用默认排序类型时生成了无效的排序查询,现在是这样。

【问题讨论】:

  • 我修复了答案中的错误并添加了有关日志记录的信息。

标签: scala sqlite quill.io


【解决方案1】:

您应该将查询重写为:

import ctx._
def saveToCache(item: Video): Unit = {
  if (ctx.run(query[Video].filter(_.id == lift(item.id)).isEmpty))
    ctx.run(query[Video].insert(lift(item)))
  else ctx.run(query[Video].filter(_.id == lift(item.id)).update(lift(item)))
  ()
}

因为quote 必须包含将被编译为单个查询的表达式。 此代码将编译为三个查询。

但最好使用优化版:

import ctx._
def saveToCacheOptimized(item: Video): Unit = {
  if (ctx.run(query[Video].filter(_.id == lift(item.id)).update(lift(item))) == 0)
    ctx.run(query[Video].insert(lift(item)))
  ()
}

编译成两个查询。

Quill 使用 SLF4J 进行日志记录,您应该阅读此项目文档。要启用日志记录,您应该添加一些日志记录后端,例如,logback:

libraryDependencies ++= Seq(
  "ch.qos.logback" % "logback-classic" % "1.2.3"
)

仅记录查询就足够了。

【讨论】:

  • 谢谢,它正在工作:)。我可能对 Quill 的期望太高了,也许是因为几年前我曾使用过 ORM。但是 Quill 似乎更接近 DB 层并且并不像我希望的那样万无一失(规则“如果它编译它是正确的”显然在这里不成立,即使使用正确的类型它也可能会失败运行时)。
  • 其实好像是个bug。我举报了it
猜你喜欢
  • 2020-05-28
  • 2011-05-21
  • 2019-07-06
  • 2014-03-03
  • 2016-07-02
  • 2020-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多