查询语句
r.GET("/delete", func(c *gin.Context) {
// 删除用户名称是 周末 的用户
class := modules.Class{}
modules.DB.Where("name = ?", "周末").Delete(&class)
c.JSON(200, gin.H{
"msg": "删除成功",
})
})
为啥golang的SQL语句是这样的
我们发现golang的删除语句是:
modules.DB.Where("name = ?", "周末").Delete(&class)
为啥不是:delete from class where name = "周末";
因为:底层SQL执行的语句就是:
delete from class where name = "周末";
只是换成了用 Go 代码拼 "SQL"的写法
打开 SQL 日志
我们想知道 modules.DB.Where("name = ?", "周末").Delete(&class) 底层执行的SQL语句是什么样的,
我们要打开SQL日志看一下;把连接改成Debug() 模式,日志就会输出。
r.GET("/delete", func(c *gin.Context) {
// 删除用户名称是 周末 的用户
class := modules.Class{}
// 这里使用 Debug() 方法,开启 SQL 日志,方便查看执行的 SQL 语句
modules.DB.Debug().Where("name = ?", "周末").Delete(&class)
c.JSON(200, gin.H{
"msg": "删除成功",
})
})
控制台会输出:
[2.378ms] [rows:1] DELETE FROM `class` WHERE name = '周末'
rows:1 表示删掉了 1 行。
这就底层执行的 SQL,是由 GORM 从TableName() +Where 条件拼出来的。
两种写法完全等价
// 写法 A:GORM 方法式(你现在的)
modules.DB.Where("name = ?", "周末").Delete(&modules.Class{})
// 写法 B:原生 SQL
modules.DB.Exec("DELETE FROM class WHERE name = ?", "周末")
| A(方法式) | B(原生 SQL) | |
|---|---|---|
| 谁拼 SQL | GORM | 你 |
| 表名从哪来 | 结构体 TableName() | 你手写 |
| 参数安全 | 自动参数化 | 用 ? 也安全,拼字符串就不安全 |
| 写错表名 | 编译期就能发现 | 运行时才报错 |
| 复杂子查询/批量 | 麻烦 | 更直接 |
所以没有"必须这样写"的规范 ,两条路都合法,只是绝大多数 GORM 项目选 A。
因为:它更方便,更安全,更符合 GORM 设计目标。
用 Go 代码拼 "SQL"的写法的好处
-
表名只维护一处。
现在表叫
class以后改成classes,只需改 TableName() ,全项目所有 CRUD 自动跟着变;
原生 SQL 里每一处都要手改。
-
防注入是结构性的
Where("name = ?", "周末") // ✅ ? 被驱动参数化
Where("name = '" + name + "'") // ❌ 用户传 OR 1=1,就全表删光
参数化不是"更安全一点",而是从机制上让注入不可能发生。
原生 SQL 用? 同样安全,但一旦有人图省事用了拼接,漏洞就进来了。
-
能接软删除、钩子、事务
如果结构体以后加了
gorm.DeletedAt字段,Delete()会自动变成UPDATE ... SET deleted_at=...(软删除),业务代码一个字都不用改。原生
DELETE语句则会真的物理删除,绕过所有框架能力。 -
换个数据库不用重写
同一份代码在 MySQL / PostgreSQL / SQLite 都能跑,SQL 方言差异由驱动处理。