为了避免DRY,我试图创建一个带有可变列名的sql INSERT语句,并通过ScalikeJDBC的sql插值填充这些列的数据:
case class MySQLInsertMessage(tableName:String, columns:List[String], values:List[String])
def depositMessage(msg: MySQLInsertMessage): Unit = {
NamedDB('MySQLMsgDepositor) localTx { implicit session =>
val sqlStmt = sql"INSERT INTO ${msg.tableName} (${msg.columns}) VALUES (${msg.values})"
println("The sql statement is: " + sqlStmt.statement)
println("The parameters are: " + sqlStmt.parameters)
sqlStmt.update().apply()
}
}
当我打电话给:
depositMessage(MySQLInsertMessage("My_Table", List("key", "email"), List("42", "[email protected]")))
生成的控制台打印输出为:
sql语句是:INSERT INTO? (?,?)VALUES(?,?)
参数是:List(My_Table,key,email,42,[email protected])
您的SQL语法有错误;查看与您的MySQL服务器版本相对应的手册,以便在''My_Table'附近使用正确的语法('key','email')VALUES('42','user @ emai'在第1行java.sql.SQLSyntaxErrorException:您的SQL语法中有错误;请查看与您的MySQL服务器版本对应的手册,以便在''My_Table'('key','email')附近使用正确的语法VALUES('42','user @ emai'在第1行
我试过把sql"..."
包裹起来:sql"""..."""
,但这似乎没有什么区别。我可以在我的MySQL工作台GUI中执行预期的语句。知道我的语法错误是什么吗?
根据@scaisEdge的提示,似乎ScalikeJDBC在使用其语法时,总是会在任何参数化值周围放置单引号。从这里判断 - https://github.com/scalikejdbc/scalikejdbc/issues/320 - 这是一个众所周知的问题。
使用MySQL INSERT
语句(或其他语句),您的表名或列值可能没有单引号,但允许它们有反引号。
你可以使用他们的SQLSyntax.createUnsafely(str:String)
方法,或者,如果我想像上面那样做,而不是使用sql"..."
,我可以使用旧的SQL(s"INSERT INTO ${msg.tableName} (${msg.columns.mkString(",")})")
方式
注意 - 我相信这两种情况都让你接受注射攻击。因为,对我来说,这是一个本地API,你必须拥有数据库的用户名和密码,无论使用它,我都会采用createUnsafely
的做事方式,一点点正则表达“清洁”,有点不优雅一点心意:
def depositMessage(msg: MySQLInsertMessage): Unit = {
NamedDB('MySQLMsgDepositor) localTx { implicit session =>
val unsafeSQLRegex = "[`'\"]".r
val table = SQLSyntax.createUnsafely(s"`${unsafeSQLRegex.replaceAllIn(msg.tableName, "")}`")
val columns = SQLSyntax.createUnsafely(msg.columns.map(value => unsafeSQLRegex.replaceAllIn(value, "")).mkString("`", "`, `", "`"))
val sqlStmt = sql"INSERT INTO $table ($columns) VALUES (${msg.values})".update().apply()
}
}
}