Go Squirrel 怎样用 Eq 安全构造可选查询条件
来源:17golang原创
时间:2026-10-29 12:23:05 430浏览 收藏
用 sq.Eq{"status": value} 为固定列名构造参数化条件,再根据参数是否提供,决定要不要调用 Where。关键是让列名由程序控制、用户值进入参数列表;不要把筛选值拼进 SQL 字符串,也不要把“没提供”误当成 false、0 或 SQL NULL。
官方地址:https://github.com/Masterminds/squirrel
Squirrel 的项目说明将其定位为已完成功能、仍接受修复的 SQL 构造器,本文解读这项已有能力,不把它包装成刚发布的新功能。适用场景是列表接口的可选筛选:状态、是否归档、负责人等参数可以分别省略。
先把可选值和SQL结构分开
传统拼接经常混合三个问题:决定条件是否出现、选择列名、表达参数值。Eq 负责后两者中的值表达,但 map 的键仍是 SQL 结构的一部分。列名必须来自代码或允许列表,不能直接把请求中的任意字段名塞进去。
多个 Where 条件通常以 AND 组合;Eq map 中多个键也构成 AND。构造器返回更新后的值,因此追加时写 query = query.Where(...),而不是调用后丢弃返回结果。官方用法见 Squirrel 项目说明。
图中的 筛选参数、提供状态 属于请求信息;固定列名、Eq、Where、SelectBuilder 属于构造职责。是否提供决定追加与否,Eq 关联固定列名和筛选值,Where 将条件加入构造器。

用指针区分未提供与零值
下面是完整的构造函数文件。它只返回 SQL 和 args,不执行数据库查询。Status=nil 表示不按状态筛选;指向空字符串则表示明确匹配空字符串。Archived 指向 false 时仍应产生条件。
package query
import (
"fmt"
sq "github.com/Masterminds/squirrel"
)
type TicketFilter struct {
Status *string
Archived *bool
OwnerID *int64
OnlyUnassigned bool
}
func BuildTicketQuery(filter TicketFilter) (string, []interface{}, error) {
// 互相矛盾的条件在应用层处理,不把组合解释留给数据库。
if filter.OnlyUnassigned && filter.OwnerID != nil {
return "", nil, fmt.Errorf("负责人和未分配条件不能同时指定")
}
query := sq.Select("id", "status", "archived", "owner_id").
From("support_tickets").
OrderBy("id DESC").
Limit(100).
PlaceholderFormat(sq.Dollar) // 本例使用 PostgreSQL 占位符。
if filter.Status != nil {
query = query.Where(sq.Eq{"status": *filter.Status})
}
if filter.Archived != nil {
// false 也是有效筛选值,不能用 if *filter.Archived 代替。
query = query.Where(sq.Eq{"archived": *filter.Archived})
}
if filter.OwnerID != nil {
query = query.Where(sq.Eq{"owner_id": *filter.OwnerID})
}
if filter.OnlyUnassigned {
// nil 的SQL语义是 IS NULL,不是忽略这个条件。
query = query.Where(sq.Eq{"owner_id": nil})
}
sqlText, args, err := query.ToSql()
if err != nil {
return "", nil, fmt.Errorf("构造工单查询失败: %w", err)
}
return sqlText, args, nil
}项目需在 go.mod 中声明并固定 github.com/Masterminds/squirrel 版本。调用方把接口参数解析成这个模型,再调用 BuildTicketQuery。指针只能保留本模型中的“提供或省略”;请求反序列化是否也保留显式 null,需要在传输模型中另外设计。
该函数允许所有可选字段都省略,结果是取前一百条工单。若产品不允许无筛选查询,应在入口额外拒绝,而不是期待 Eq 自动限制结果范围。Limit 也不替代租户权限条件。
让 Eq 处理 NULL 和列表语义
| 条件 | SQL含义 | 应用注意点 |
|---|---|---|
| 不调用 Where | 该条件省略 | 这才是不按该字段筛选 |
| Eq{"owner_id": nil} | owner_id IS NULL | 明确匹配无负责人 |
| Eq{"owner_id": int64(0)} | 等于占位参数0 | 0不是省略或NULL |
| Eq{"id": []int64{7, 11}} | id IN 两个占位参数 | 列表元素成为参数 |
| Eq{"id": []int64{}} | 恒假条件 | 不是取消id筛选 |
nil 切片与未提供切片应在接口层明确约定:如果你把切片作为 Eq 的值传进去,它按列表语义处理;如果需要空列表表示“不筛选”,就根据长度决定是否追加 Where。某些业务需要空集合表示“无任何可访问记录”,此时保留恒假条件反而符合要求。
另外,[]byte 通常作为数据库标量字节数据处理,不按普通切片生成 IN;[]uint8 与它是同一类型,不能通过改名绕过。列表与 nil 的构造逻辑见 Eq 实现。IN 列表中混入 nil 也不能代替显式的 IS NULL 分支。
ToSql 之后保持 SQL 与 args 配对
ToSql 返回两项需要一起使用的数据:带占位符的 SQL 和按相应次序排列的参数。数据库调用形态应保持为 db.QueryContext(ctx, sqlText, args...)。不能把 args 再格式化、替换进 SQL 文本后发送。
第二张图的 SelectBuilder、ToSql、SQL文本、args、占位符格式、QueryContext 表示构造结果及使用关系:构造器配置占位符,ToSql 产生文本与参数,QueryContext 同时依赖二者。

本例使用 Dollar 格式,面向接受 $1、$2 形式的驱动;使用问号占位符的驱动应选择对应格式。参数顺序由构造器生成,不要按请求参数的到达顺序自行重排 args,也不要从 map 遍历顺序猜测绑定位置。
哪些输入仍需要由应用控制
Eq 不是完整的查询权限系统。租户条件应来自认证上下文并由程序固定追加;排序字段、表名、连接片段和任意表达式仍属于结构,必须单独控制。参数化处理的是值,不会让一个恶意列名自动变安全。
和旧的字符串拼接方式相比,Eq 让普通等值、NULL 和 IN 条件更清楚,但也引入了需要记住的约定:nil 不是省略、空列表不是不限范围、切片类型影响 SQL 形态。采用时把这些约定放在统一查询函数中,避免每个接口各自解释。
状态是空字符串,Eq 会自动忽略吗?
不会。它仍然是一个值。若接口规定空字符串代表不筛选,应先在参数解析层规范化为未提供状态,不能依赖 Eq 猜测业务意图。
可以把“status =”作为 Eq 的键吗?
Eq 的键应是受控的列名或预先设计的 SQL 标识表达,不应拼上等号等运算片段。本例仅使用硬编码列名;其他比较关系选择对应构造类型。
ToSql 成功是否证明查询一定能执行?
不能。它证明构造器成功生成了文本与参数,不会访问数据库来确认表结构、字段类型、索引或权限。数据库执行错误仍由调用层处理,本文没有运行查询或声称线上执行成功。
-
860 收藏
-
843 收藏
-
826 收藏
-
809 收藏
-
792 收藏
-
302 收藏
-
334 收藏
-
135 收藏
-
232 收藏
-
355 收藏
-
360 收藏
-
446 收藏
-
210 收藏
-
200 收藏
-
187 收藏
-
208 收藏
-
164 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习