sqlc只生成查询逻辑代码,不自动导入database/sql或数据库驱动,需手动配置驱动注册、连接池及context支持;占位符必须用$1格式,且driver配置仅影响sql解析与类型映射。

sqlc 生成的代码为什么跑不起来?
常见现象是 go run 报错:找不到 QueryRow 方法,或类型不匹配——根本原因不是 sqlc 用错了,而是它只生成「查询逻辑」,不帮你配数据库驱动和连接池。
- sqlc 不会自动 import
"database/sql"或具体驱动(如"github.com/lib/pq"),你得自己加 - 生成的 struct 和方法依赖
sql.NullString这类类型,但如果你没在db.go里注册驱动,sql.Open会 panic - 别直接
go run main.go就完事,先确认sqlc generate后生成的db/下有queries.sql.go和models.go,且路径被go mod正确识别
sqlc.yaml 配置里 driver: postgres 是什么意思?
它只告诉 sqlc:「按 PostgreSQL 的语法解析 SQL、按 pg 的类型映射生成 Go 类型」,和运行时用什么数据库无关。哪怕你最终连的是 CockroachDB 或本地 SQLite(通过适配层),只要 SQL 写法兼容 pg,这个配置就成立。
-
driver: "postgresql"(注意不是postgres)才是 sqlc v1.20+ 推荐写法,旧版写postgres会警告 - 如果 SQL 文件里用了
RETURNING *,而你配了driver: "mysql",sqlc 会直接报错:不支持该语法 —— 它真正在意的是「SQL 能不能被它 parse 通」 - 生成的代码里不会出现
pgx或pq,所有 DB 操作仍走标准*sql.DB,换驱动只需改sql.Open("pgx", ...)这一行
怎么让 sqlc 生成带 context 的方法?
默认生成的是无 context 版本(比如 GetUser(id int) (User, error)),要启用 context 支持,必须在 sqlc.yaml 里显式打开:
version: "2" packages: - name: "db" path: "./db" queries: "./query/*.sql" schema: "./schema.sql" engine: "postgresql" emit_json_tags: true emit_interface: true emit_exact_table_names: true emit_empty_slices: true <strong>emit_method_comments: true</strong><strong>emit_pointers_for_null_types: true</strong><strong>emit_db_tags: true</strong><strong>emit_exported_queries: true</strong><strong>emit_interface: true</strong> # ?关键项 <strong>emit_context: true</strong>
加了 emit_context: true 后,方法签名变成 GetUser(ctx context.Context, id int) (User, error),且所有内部调用都透传 ctx —— 但注意:sqlc 不管你传进来的是 context.Background() 还是带 timeout 的,它只负责把参数接住、往下传。
- 没开这个选项,硬在调用侧加 context.WithTimeout 也没用,底层还是阻塞式调用
- 开了之后,若你用的是
pgx/v5驱动,context 才真正生效;用lib/pq则仅对连接建立阶段起作用(执行阶段不中断) - 别指望 sqlc 自动生成
WithCancel或超时逻辑,那是你业务层的事
SQL 文件里写 $1 还是 ?,会不会影响生成?
sqlc 强制要求使用 PostgreSQL 风格的占位符:$1, $2…… 它不认 MySQL 的 ? 或命名参数 :name。写错直接报错:error: unsupported placeholder "?": only "$N" style is supported。
- 即使你最终连的是 MySQL,只要配置
driver: "postgresql",SQL 就得按 pg 写法来(比如用ILIKE而非LIKE+LOWER()) -
WHERE id = $1 AND name ILIKE $2这种写法会被正确映射为两个参数,顺序严格对应,别指望它自动重排 - 嵌套 CTE 或
VALUES子句里也得用$1,例如INSERT INTO users VALUES ($1, $2)—— sqlc 不做语义分析,只做语法树解析
sqlc 的边界很清晰:它是个 SQL 到 Go 的翻译器,不是 ORM,也不封装连接管理。最容易卡住的地方,往往是以为它“该干的都干了”,结果发现连 sql.Open 都得自己写三行。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











