Go反射不生成SQL但可映射结构体字段为SQL条件或字段,需用reflect.StructTag提取db tag(如db:"name"),避免用Field.Name;遇db:"-"或空则跳过,db:"omitempty"需判零值;WHERE条件应拼"col=?"并分离参数切片防注入。

Go 的反射本身不生成 SQL,但能帮你把结构体字段映射成 WHERE 条件或 SELECT 字段 —— 关键是别让它拼接完整语句,否则容易 SQL 注入、类型错乱、NULL 处理失控。
用 reflect.StructTag 提取字段映射关系
结构体字段必须带明确的 tag(比如 db:"name"),否则反射拿不到列名;tag 里最好支持 omitempty 和 ignore 控制行为。
常见错误:直接用 reflect.Value.Field(i).Name 当列名 —— 这拿到的是 Go 字段名(UserName),不是数据库列(user_name),一查就空。
- 必须读
structField.Tag.Get("db"),不是structField.Name - 遇到
db:"-"或空字符串,跳过该字段 - 遇到
db:"id,omitempty",要检查值是否为零值(reflect.Zero判定)再决定是否加入条件
生成 WHERE 条件时,只输出 key = ? 和参数切片
别用反射拼出 "WHERE name = 'foo'" 这种字符串 —— 字符串插值无法防注入,也无法处理 time.Time、nil、[]byte 等类型。
正确做法:遍历字段,对每个非忽略/非空字段,追加 "column = ?" 到条件切片,并把对应值 append 到 args 切片。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
示例逻辑片段:
reflect.Type
- 键用
reflect.Type.String(),值是自定义结构体type dbField struct { Col string; Omit bool; Index int } - 首次访问时解析一次,后续直接查 map
- 注意:不能缓存
reflect.Value(含运行时状态),只能缓存Type和 tag 解析结果
复杂字段(指针、嵌套、slice)不建议自动处理
反射可以读 *string,但要不要解引用?如果值是 nil,该生成 IS NULL 还是跳过?嵌套结构体该展开成 user_profile.name 还是报错?这些没有通用解法。
真实项目中,这类字段应显式排除(db:"-"),或由上层业务代码单独构造条件 —— 反射只负责“扁平、可直译”的字段。
最容易被忽略的一点:sql.NullString、sql.NullInt64 等类型,其 Valid 字段才是判断是否参与查询的依据,不是看 String 字段本身;反射不会自动识别它们,必须手动特判。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










