【问题标题】:Anorm String Interpolation not replacing variables异常字符串插值不替换变量
【发布时间】:2015-01-10 00:46:39
【问题描述】:

我们正在使用 Scala Play,我正在努力确保所有 SQL 查询都使用 Anorm 的字符串插值。它适用于某些查询,但许多查询实际上并没有在查询执行之前替换变量。

import anorm.SQL
import anorm.SqlStringInterpolation

object SecureFile 
{
  val table = "secure_file"
  val pk = "secure_file_idx"
  ...

// This method works exactly as I would hope
def insert(secureFile: SecureFile): Option[Long] = {
  DBExec { implicit connection =>
    SQL"""
      INSERT INTO secure_file (
        subscriber_idx,
        mime_type,
        file_size_bytes,
        portal_msg_idx
      ) VALUES (
        ${secureFile.subscriberIdx},
        ${secureFile.mimeType},
        ${secureFile.fileSizeBytes},
        ${secureFile.portalMsgIdx}
        )
      """ executeInsert()
    }
  }

def delete(secureFileIdx: Long): Int = {
  DBExec { implicit connection =>
    // Prints correct values
    println(s"table: ${table} pk: ${pk} secureFileIdx: ${secureFileIdx} ")

    // Does not work
    SQL""" 
      DELETE FROM $table WHERE ${pk} = ${secureFileIdx} 
    """.executeUpdate()

    // Works, but unsafe
    val query = s"DELETE FROM ${table} WHERE ${pk} = ${secureFileIdx}" 
    SQL(query).executeUpdate() 
  }
}
....
}

在 PostgreSQL 日志中,很明显 delete 语句没有获取正确的值:

2015-01-09 17:23:03 MST ERROR:  syntax error at or near "$1" at character 23
2015-01-09 17:23:03 MST STATEMENT: DELETE FROM $1 WHERE $2 = $3
2015-01-09 17:23:03 MST LOG:  execute S_1: ROLLBACK

我尝试了许多不同的 execute、executeUpdate 和 executeQuery,结果相似。目前,我们正在使用基本的字符串替换,但这当然不好,因为它没有使用 PreparedStatements。

【问题讨论】:

  • 对Anorm插值、标准Scala插值和PreparedStatement存在误解。

标签: scala playframework-2.3 anorm


【解决方案1】:

对于坐在此页面上的其他人,他们摸不着头脑,想知道他们可能会丢失什么......

SQL("select * from mytable where id = $id") 

不一样
SQL"select * from mytable where id = $id" 

前者不做字符串插值,而后者做。

这在上述文档中很容易被忽略,因为提供的所有样本恰好都有一个(不相关的)右括号(就像这句话一样)

【讨论】:

  • 谢谢!我花了太多时间想知道为什么我得到 ERROR: syntax error at or near "{" 语法类似于{id},直到我找到了这个并尝试了带括号的SQL()
【解决方案2】:

引入了异常字符串插值来传递参数(例如SQL"Select * From Test Where id = $x),并根据适当的类型转换在底层PreparedStament 上设置插值参数(例如$x)(请参阅https://www.playframework.com/documentation/2.3.x/ScalaAnorm 上的用例)。

下一个 Anorm 版本还将使用 #$foo 语法来混合参数插值和标准字符串插值。这将允许编写DELETE FROM #$table WHERE #${pk} = ${secureFileIdx} 并使其作为DELETE FROM foo WHERE bar = ? 执行(如果文字table"foo" 并且pk"bar"),文字secureFileIdx 作为参数传递。见相关pull request

在下一个版本发布之前,您可以从它的主资源构建 Anorm,以受益于此更改。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-15
    • 2013-02-16
    • 1970-01-01
    • 1970-01-01
    • 2020-07-09
    • 2014-06-12
    • 2022-06-15
    • 2011-09-29
    相关资源
    最近更新 更多