当前位置: 首页 > news >正文

Gorm(十四)的多条件叠加

一、例子

package mainimport ("fmt""gorm.io/driver/sqlite""gorm.io/gorm"
)type User struct {ID     uintStatus int
}func main() {db, _ := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})db.AutoMigrate(&User{})db.Create(&User{Status: 1})db.Create(&User{Status: 2})var c1, c2 int64db.Where("status = 1").Count(&c1)db.Where("status = 2").Count(&c2)
}

你观察到的“条件叠加”并不是 SQL 或 GORM 的锅,而是 GORM 的链式 API 在 同一个 *gorm.DB 实例上不断追加条件 导致的。
把两段代码拆开看就明白了:

// 第一次调用
db.Where("status = 1").Count(&c1)
// 等价于
// SELECT count(*) FROM users WHERE status = 1;// 第二次调用
db.Where("status = 2").Count(&c2)
// 等价于
// SELECT count(*) FROM users WHERE status = 1 AND status = 2;

为什么第二次会带上第一次的 status = 1
因为 db.Where(...) 返回的是 同一个底层 *gorm.DB 指针的副本,副本共享了内部的 Statement 对象;于是第二次 Where 只是往同一份 Statement 里再追加了一个条件,最终 SQL 里就出现了 status = 1 AND status = 2,结果当然是 0 行。

官方文档里把这种现象叫做“复用同一个 DB 会话导致条件累积”。

解决办法:每次查询都用一个新的会话,或者显式重置条件。

// 方法 1:链式调用完后不再复用
db.Where("status = 1").Count(&c1)
db.Session(&gorm.Session{}).Where("status = 2").Count(&c2) // 新 Session// 方法 2:直接新建一个 DB 副本
db2 := db.Session(&gorm.Session{})
db2.Where("status = 2").Count(&c2)// 方法 3:用 Scopes(推荐)
countByStatus := func(st int) func(d *gorm.DB) *gorm.DB {return func(d *gorm.DB) *gorm.DB {return d.Where("status = ?", st)}
}
db.Scopes(countByStatus(1)).Count(&c1)
db.Scopes(countByStatus(2)).Count(&c2)

一句话:
GORM 的链式条件会累积在同一个 *gorm.DB 实例上,想隔离就换 Session 或用 Scopes。

在 GORM 里,只要返回值仍然是 *gorm.DB 的“链式方法”,都会把条件累积到同一个 Statement 实例上。
下面把常见方法按“会叠加 / 不会叠加”两类给你列出来,一眼就能记住。


一、会叠加(链式继续返回 *gorm.DB

这些调用不会立即发 SQL,只是把子句写进 Statement,所以多次调用就会“叠”:

方法/关键字叠加效果举例
Where / Or / Not条件越拼越多
Select字段会被覆盖成最后一次的,但旧字段缓存还在,容易出错
Omit同 Select,最后一次生效,但列表会累积
Joins多次调用会把 JOIN 子句串起来
Group字符串直接拼接,多调一次就多一段 GROUP BY
Having同 Where,会 AND 连接
Order多调一次就多一段 ORDER BY,逗号分隔
Limit / Offset后一次直接覆盖前一次,不会累积,但仍然作用在同一个 Statement
Scopes每个 Scope 拿到的都是同一个 *gorm.DB,里面如果改了条件也会叠
Preload / Joins 预加载多次 Preload 会往 Statement.Preloads 里追加,不会覆盖
Distinct只是设置一个 bool 标志,重复调用无影响,但仍属于同一 Statement

二、不会叠加(立即执行或返回非 DB 类型)

一旦调用下列方法,GORM 会立即生成 SQL 并清空(或新建)Statement,后续再用原来的 *gorm.DB 也不会互相污染:

方法说明
Create / CreateInBatches插入后立即执行,内部会复用 Statement,但返回的 *gorm.DB 已经 finish
First / Take / Last / Find查询后立即执行,返回的 *gorm.DBStatement 已 reset
Update / Updates / UpdateColumn更新后立即执行
Delete删除后立即执行
Count / Pluck / Scan / Row / Rows聚合/扫描类方法,执行后立即 reset
Transaction / Session显式新建作用域,内部是一个干净的 Statement

三、一句话总结

  1. 只要方法签名返回的还是 *gorm.DB没真正发 SQL,就会继续往同一个 Statement 里写条件。
  2. 想隔离就 db.Session(&gorm.Session{})db.WithContext(ctx) 新建会话,或者把链式调用拆成局部变量。
  3. 真正执行的那一步(FindCreateUpdateDeleteCount…)会把当前 Statement 消费掉,之后再用原指针也不会污染。
http://www.dtcms.com/a/597723.html

相关文章:

  • 网站设计班培训郑州网站关键词排名技术代理
  • 网络流dinic与EK
  • 网络编程核心:套接字绑定(bind函数)与 IP 地址转换处理
  • 百度建站东莞著名网站建设
  • 如何选择邯郸网站制作做外贸网站维护费是多少
  • 【SCI复现】高比例可再生能源并网如何平衡灵活性与储能成本?虚拟电厂多时间尺度调度及衰减建模
  • CodeBuddy AI IDE:全栈AI开发平台实战
  • 购物网站开发教程 视频大流量网站 文章点击
  • 研究人员诱导ChatGPT对自身实施提示注入攻击
  • 数据结构与算法实验(黑龙江大学)
  • 孤客截图工具 Pro - 从开发到打包的完整指南
  • 山东德州最大的网站建设教学学校网站php源码|班级主页教师博客学生博客|学校网站织梦仿
  • 基于librespot的定制化Spotify客户端开发:开源替代方案的技术实践与优化
  • 主从同步配置的步骤
  • 个人使用网站wordpress用户设置
  • vps网站目录是灰色的生活中实用的产品设计
  • mysql主备配置(对比postgresql)
  • mysql tidb like查询有换行符内容问题解决
  • 【工具变量】上市公司是否获得ZF采购DID(2000-2025年)
  • 【AI学习-comfyUI学习-LCM lora八步生成 工作流-各个部分学习-第八节】
  • 转轮机加密(攻防世界)
  • 微信小程序实现长按复制选中文字的效果
  • SQL Server 驱动 和 TLS 版本不兼容 的问题
  • 【低空安全】低空无人机集群侦测与反制概述
  • 制作网站的原因是计算机网页制作工具
  • 机器学习聚类k均值簇数的调优方法
  • 批量格式化XML与JSON文件小工具
  • TensorFlow深度学习实战(41)——TensorFlow生态系统
  • 网站空格 教程宁波龙山建设有限公司网站
  • 4-ARM-PEG-COOH(2),多功能羧基PEG的结构特性与反应特点