sqlc 用于 Go:从 SQL 生成类型安全代码
\n\nsqlc 是一个编译器,它根据您的 SQL 查询生成 Go 代码。您无需手动编写与数据库交互的函数,只需编写纯 SQL,sqlc 就会为您生成类型化、安全且高效的函数。这与 ORM 有着根本的不同:您保留对 SQL 的完全控制,同时摆脱了编写样板代码的繁琐工作。
\n\n为什么需要它?首先,sqlc 在编译时保证了类型安全。如果您更改了表结构或查询,sqlc 会重新生成代码,Go 编译器会立即指出所有需要修改的地方。其次,性能方面:生成的代码不使用反射,也不进行多余的内存分配,使其几乎与通过 database/sql 手动编写查询一样快。第三,它简化了代码审查:SQL 查询在 .sql 文件中清晰可见,而不是隐藏在 ORM 的方法中。
sqlc 非常适合那些注重性能和查询控制的项目:高负载 API、金融系统、分析平台。它还能很好地与数据库迁移工具(例如 golang-migrate)配合使用,并且不绑定特定的数据库管理系统——支持 PostgreSQL、MySQL、SQLite。
\n\n安装
\n\nsqlc 不是一个库,而是一个命令行工具。可以通过以下几种方式安装:
\n\n# 通过 go install 安装(推荐)\ngo install github.com/sqlc-dev/sqlc/cmd/sqlc@latest\n\n# 通过 Homebrew 安装(macOS/Linux)\nbrew install sqlc\n\n# 从 GitHub 下载二进制文件\n# https://github.com/sqlc-dev/sqlc/releases\n\n安装后检查版本:
\n\nsqlc version\n\n快速开始
\n\n让我们创建一个演示 sqlc 工作的最小项目。
\n\n1. 项目结构
\n\nmkdir sqlc-demo && cd sqlc-demo\ngo mod init sqlc-demo\n\n2. sqlc 配置
\n\n在项目根目录创建 sqlc.yaml 文件:
version: "2"\nsql:\n - engine: "postgresql"\n queries: "queries.sql"\n schema: "schema.sql"\n gen:\n go:\n package: "db"\n out: "db"\n sql_package: "pgx/v5"\n\n3. 数据库模式
\n\nschema.sql 文件:
CREATE TABLE authors (\n id BIGSERIAL PRIMARY KEY,\n name text NOT NULL,\n bio text\n);\n\n4. SQL 查询
\n\nqueries.sql 文件:
-- name: GetAuthor :one\nSELECT * FROM authors\nWHERE id = $1;\n\n-- name: ListAuthors :many\nSELECT * FROM authors\nORDER BY name;\n\n-- name: CreateAuthor :one\nINSERT INTO authors (name, bio)\nVALUES ($1, $2)\nRETURNING *;\n\n-- name: DeleteAuthor :exec\nDELETE FROM authors\nWHERE id = $1;\n\n5. 生成代码
\n\nsqlc generate\n\n执行后,db/ 文件夹中会出现生成的代码文件。现在可以在代码中使用它们:
package main\n\nimport (\n "context"\n "fmt"\n "log"\n\n "github.com/jackc/pgx/v5/pgxpool"\n "sqlc-demo/db"\n)\n\nfunc main() {\n ctx := context.Background()\n pool, err := pgxpool.New(ctx, "postgres://user:pass@localhost:5432/testdb")\n if err != nil {\n log.Fatal(err)\n }\n defer pool.Close()\n\n queries := db.New(pool)\n\n // 创建作者\n author, err := queries.CreateAuthor(ctx, db.CreateAuthorParams{\n Name: "Brian Kernighan",\n Bio: "Co-author of The C Programming Language",\n })\n if err != nil {\n log.Fatal(err)\n }\n fmt.Printf("Created author: %+v\\n", author)\n\n // 根据 ID 获取作者\n fetched, err :=