使用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

这真是太奇怪了。cry 有人知道问题出在哪里吗?谢谢!


5 回复

并非所有内容都可以参数化,CREATE USER 就是一个例子。

为什么你要从应用程序中创建数据库用户?


哇,这个方法看起来可行。我明天会试试,非常感谢!smile

所以这不是一个错误,而是一个特性?实际上,我想为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)。

回到顶部