当前位置:首页 > 文章列表 > Golang > Go教程 > Go Squirrel 怎样用 Eq 安全构造可选查询条件

Go Squirrel 怎样用 Eq 安全构造可选查询条件

来源:17golang原创 2026-10-29 12:23:05 0浏览 收藏

用 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 将条件加入构造器。

可选参数与固定列名构造Eq条件的静态结构图
结构图:参数是否提供与条件表达分别处理,SQL列名保持由程序控制。连线表示依赖,不是执行步骤。

用指针区分未提供与零值

下面是完整的构造函数文件。它只返回 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)}等于占位参数00不是省略或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 同时依赖二者。

Squirrel SQL文本与args保持配对的静态依赖图
结构图:占位符文本与参数列表配套交给数据库驱动,不进行字符串替换。图示不是数据库运行证据。

本例使用 Dollar 格式,面向接受 $1、$2 形式的驱动;使用问号占位符的驱动应选择对应格式。参数顺序由构造器生成,不要按请求参数的到达顺序自行重排 args,也不要从 map 遍历顺序猜测绑定位置。

哪些输入仍需要由应用控制

Eq 不是完整的查询权限系统。租户条件应来自认证上下文并由程序固定追加;排序字段、表名、连接片段和任意表达式仍属于结构,必须单独控制。参数化处理的是值,不会让一个恶意列名自动变安全。

和旧的字符串拼接方式相比,Eq 让普通等值、NULL 和 IN 条件更清楚,但也引入了需要记住的约定:nil 不是省略、空列表不是不限范围、切片类型影响 SQL 形态。采用时把这些约定放在统一查询函数中,避免每个接口各自解释。

状态是空字符串,Eq 会自动忽略吗?

不会。它仍然是一个值。若接口规定空字符串代表不筛选,应先在参数解析层规范化为未提供状态,不能依赖 Eq 猜测业务意图。

可以把“status =”作为 Eq 的键吗?

Eq 的键应是受控的列名或预先设计的 SQL 标识表达,不应拼上等号等运算片段。本例仅使用硬编码列名;其他比较关系选择对应构造类型。

ToSql 成功是否证明查询一定能执行?

不能。它证明构造器成功生成了文本与参数,不会访问数据库来确认表结构、字段类型、索引或权限。数据库执行错误仍由调用层处理,本文没有运行查询或声称线上执行成功。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go Cron 怎样在关闭调度器时等待正在执行的任务Go Cron 怎样在关闭调度器时等待正在执行的任务
上一篇
Go Cron 怎样在关闭调度器时等待正在执行的任务
Go Squirrel 怎样用 Expr 把表达式与绑定参数组合起来
下一篇
Go Squirrel 怎样用 Expr 把表达式与绑定参数组合起来
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    774次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    770次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    856次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    821次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    651次使用