使用Gorm执行MySQL操作时遇到的错误
使用Gorm执行MySQL操作时遇到的错误
大家好,我正在尝试使用 gorm 为我的本地 MySQL 创建一个新用户,但当我尝试在 gormdb.Exec 中使用 “?” 时失败了:
err := db.Exec("CREATE USER ? IDENTIFIED BY ?", a.Name, a.Pwd).Error
它返回了错误:
[1.824ms] [rows:0] CREATE USER 'Reiis' IDENTIFIED BY '12345'
Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? IDENTIFIED BY ?' at line 1
看起来 gorm 没有用 a.Name 替换 “?”?但它在屏幕上打印出的 SQL 语句又是正确的。
当我尝试运行下面的代码时,它却可以正常工作:
cmd := fmt.Sprintf("CREATE USER '%s' IDENTIFIED BY '%s'", a.Name, a.Pwd)
err := db.Exec(cmd).Error
这真是太奇怪了。
有人知道问题出在哪里吗?谢谢!
5 回复
并非所有内容都可以参数化,CREATE USER 就是一个例子。
为什么你要从应用程序中创建数据库用户?
哇,这个方法看起来可行。我明天会试试,非常感谢!
所以这不是一个错误,而是一个特性?实际上,我想为MySQL集群实现某种控制管理器,并使用GORM来避免SQL注入。是否有更好的方法来实现这些功能?谢谢!
我不认为这是一个功能;只是一个“限制”。也许这个限制可以被视为一个错误。我不熟悉MySQL,但你可能可以通过类似这样的方式间接实现:
db.Exec(`
SET @username = ?;
SET @password = ?;
SET @sql = CONCAT("CREATE USER ", QUOTE(@username), " IDENTIFIED BY ", QUOTE(@password), ";");
PREPARE stmt FROM @sql;
EXECUTE stmt;
`, a.Name, a.Pwd)
这个问题是因为GORM的预处理语句参数占位符与MySQL的CREATE USER语句不兼容。GORM会将?替换为带引号的参数值,但MySQL的CREATE USER语法要求用户名和密码标识符不能加引号。
正确的做法是使用字符串拼接,就像你第二个示例那样。以下是改进后的代码:
// 安全地转义用户名和密码
name := db.Statement.DB.Quote(a.Name)
pwd := db.Statement.DB.Quote(a.Pwd)
cmd := fmt.Sprintf("CREATE USER %s IDENTIFIED BY %s", name, pwd)
err := db.Exec(cmd).Error
或者使用更简洁的方式:
err := db.Exec(fmt.Sprintf("CREATE USER '%s' IDENTIFIED BY '%s'",
strings.ReplaceAll(a.Name, "'", "''"),
strings.ReplaceAll(a.Pwd, "'", "''"))).Error
对于需要直接执行原生SQL语句的情况,特别是DDL语句,建议使用字符串格式化而不是参数占位符。GORM的参数替换主要适用于DML操作(SELECT、INSERT、UPDATE、DELETE)。

