我们正在使用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日志中,很明显删除语句没有获取正确的值:
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。
答案 0 :(得分:4)
引入Anorm字符串插值来传递参数(例如SQL"Select * From Test Where id = $x
),并根据正确的类型转换在基础$x
上设置插值参数(例如PreparedStament
)(请参阅{{上的用例} 3}})。
下一个Anorm版本还将使用#$foo
语法将参数插值与标准字符串插值混合。这将允许写DELETE FROM #$table WHERE #${pk} = ${secureFileIdx}
并将其作为DELETE FROM foo WHERE bar = ?
执行(如果文字table
是"foo"
且pk
是"bar"
),则使用文字secureFileIdx
作为参数传递。请参阅相关的https://www.playframework.com/documentation/2.3.x/ScalaAnorm。
在下一版本发布之前,您可以从其主要来源构建Anorm,并从此更改中受益。
答案 1 :(得分:4)
对于坐在这个页面上的任何人都挠头,想知道他们可能会遗漏什么......
SQL("select * from mytable where id = $id")
与
不同SQL"select * from mytable where id = $id"
前者不进行字符串插值,后者则不进行。
在上述文档中很容易忽略这一点,因为所提供的所有样本恰好都有一个(非相关的)右括号(就像这句话一样)