sqlc未按预期生成struct字段的常见原因是未启用emit_db_tags,导致database/sql无法通过db tag匹配列名;SELECT *会破坏类型安全,因sqlc仅按SQL文本推导类型;jsonb默认映射为[]byte;需在sqlc.yaml中设置emit_context: true以生成带context的方法。

sqlc 生成的代码为什么没按预期生成 struct 字段?
常见原因是数据库列名含下划线(如 created_at),而 sqlc 默认使用 snake_case 到 CamelCase 的映射规则,但若未启用 emit_json_tags 或 emit_db_tags,生成的 struct 字段可能无法被 database/sql 正确扫描。检查你的 sqlc.yaml 是否包含:
packages:
- name: db
path: ./db
queries: "./query/*.sql"
schema: "./schema.sql"
engine: postgres
emit_json_tags: true
emit_db_tags: true
漏掉 emit_db_tags: true 会导致 Scan 失败——Go 的 database/sql 依赖 db tag 匹配列名,不是靠字段顺序。
SQL 文件里写 SELECT * 会破坏类型安全吗?
会。sqlc 不解析运行时表结构,它只按 SQL 文本推导返回类型。用 SELECT * 时,一旦数据库加字段或改顺序,生成的 Go struct 就可能多出未声明字段,或字段类型错位,且编译器无法捕获。
- 永远用显式列名:
SELECT id, name, created_at FROM users - 若需兼容多版本表结构,用视图封装,再让 sqlc 针对视图生成
-
SELECT *在 migration 脚本或 ad-hoc 查询中可用,但绝不能进query/*.sql
PostgreSQL jsonb 字段怎么映射到 Go 类型?
sqlc 默认把 jsonb 映射为 []byte,不是 map[string]interface{} 或自定义 struct。这是有意为之:避免运行时解析失败,也保留原始字节供按需解码。
实际用法建议:
- 在查询中用
jsonb_populate_record提前展开成行(适合固定结构) - 或在 Go 层用
json.Unmarshal手动转,配合sql.NullString或自定义type JSONB []byte实现Scanner/Valuer - 不要依赖 sqlc 自动生成“智能 json 解析”——它不做 schema 推断,也不支持嵌套结构自动展开
如何让 sqlc 生成带 context 的方法?
默认生成的是无 context 版本(如 GetUser(id int) (User, error))。要支持 cancel / timeout,必须在 sqlc.yaml 中开启:
packages:
- name: db
# ...
emit_interface: true
emit_exact_table_names: false
emit_pointers_for_null_types: true
emit_empty_slices: true
emit_exported_queries: true
# 关键项:
emit_context: true
开启后,所有函数签名变成 GetUser(ctx context.Context, id int) (User, error),且生成的 Queries struct 持有 *sql.DB 和可选的 Conn,方便传入事务上下文。
注意:如果已有调用方没传 context.Background(),编译直接报错——这反而是好事,逼你补全超时控制。
sqlc 的类型安全不来自魔法,而来自“SQL 即契约”:你写的每一行 SELECT,都对应一个不可变的 Go 类型。最容易被忽略的,是把它当成 ORM 用——它不管理对象生命周期,不支持懒加载,也不做变更追踪。只要守住 SQL 显式性、context 可控性、jsonb 字节化这三点,生成的代码就能稳跑两年。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











