ScalikeJDBC SQL插值语法错误:动态INSERT语句实现问题
解决ScalikeJDBC动态列INSERT的语法错误问题
你在尝试用ScalikeJDBC构建动态列的INSERT语句时踩了个常见的坑——直接用列表插值会导致语法错误,因为ScalikeJDBC对集合类型的插值逻辑和我们预期的不一样。让我帮你拆解问题并修复代码:
问题根源
ScalikeJDBC的SQL插值中,直接使用${msg.columns}和${msg.values}会把整个列表当作单个参数处理,最终生成的SQL会变成类似这样的错误格式:
INSERT INTO your_table ('col1, col2') VALUES ('val1, val2')
显然,列名被当成了带引号的字符串,值也被合并成了一个字符串,这完全不符合SQL语法要求。
正确的实现方式
我们需要分别处理列名(SQL标识符)和值(参数):
- 列名需要转换成ScalikeJDBC的
SQLSyntax类型,用sqls.csv拼接成合法的标识符列表(不带引号) - 值列表可以直接用
sqls.csv处理成参数化的占位符,避免SQL注入
修正后的代码
case class MySQLInsertMessage(tableName: String, columns: List[String], values: List[String]) def depositMessage(msg: MySQLInsertMessage): Unit = { NamedDB('MySQLMsgDepositor) localTx { implicit session => // 处理列名:转换为SQL标识符并拼接 val columnSyntax = msg.columns.map(SQLSyntax.createUnsafely) val columnsSql = sqls.csv(columnSyntax: _*) // 处理值:直接用sqls.csv生成参数化的占位符 val valuesSql = sqls.csv(msg.values: _*) val sqlStmt = sql"INSERT INTO ${SQLSyntax.createUnsafely(msg.tableName)} ($columnsSql) VALUES ($valuesSql)" println("The sql statement is: " + sqlStmt.toString()) // 执行语句 sqlStmt.update().apply() } }
关键细节解释
SQLSyntax.createUnsafely:用于创建SQL标识符(表名、列名),因为这些部分不能参数化,需要你确保传入的tableName和columns是安全的(避免用户输入直接传入,防止SQL注入)。sqls.csv:专门用于拼接逗号分隔的SQL片段,对于标识符列表会生成col1, col2, col3的格式,对于参数列表会生成?, ?, ?的占位符(实际执行时会绑定对应的值)。- 表名同样需要用
SQLSyntax.createUnsafely处理,否则也会被当成字符串参数加上引号。
这样修改后,生成的SQL就会是合法的格式:
INSERT INTO your_table (col1, col2) VALUES (?, ?)
既符合SQL语法,又保证了值的参数化,避免SQL注入风险。
内容的提问来源于stack exchange,提问作者NateH06
相关产品推荐
相关产品推荐

