Golang: sqlc 和 goose 最佳实践

sqlc 和 goose 最佳实践

最近有使用 Golang 来写一些小的项目,需要使用到数据库,之前有使用过 GORM 这种 ORM 框架,开发起来非常方便,但是发现项目的代码多了之后管理起来不是非常方便,所以学习了一下 goose 和 sqlc 这两个工具,这篇文章就是总结一下两个工具如何搭配使用。

goose 数据库版本迁移工具

安装

goose 是 Go 语言写的一个数据库迁移工具,能够以版本控制的方式帮我们管理数据库当中的表。

在使用 goose 之前需要使用下面的命令进行安装。

zsh 复制代码
go install github.com/pressly/goose/v3/cmd/goose@latest

出现如下命令说明成功安装了 goose

使用

1. 配置环境变量

在使用 goose 的时候默认会读取环境变量当中的 GOOSE_DRIVERGOOSE_DBSTRINGGOOSE_MIGRATION_DIR 三个环境变量。

  • GOOSE_DRIVER : goose 在执行数据库迁移的时候使用的数据库驱动类型
  • GOOSE_DBSTRING : goose 在执行数据库迁移的时候使用的数据库链接 URL
  • GOOSE_MIGRATION_DIR:goose 读取的迁移文件目录

当然,goose 不止有上面三个环境变量的配置,更多的可以查看官方介绍文档。

pressly.github.io/goose/docum...

也可以像下面这样,创建一个 .env 文件,然后写入相关的内容,在使用 goose 的时候会默认载入 .env 当中的环境变量配置。

env 复制代码
GOOSE_DRIVER=postgres  
GOOSE_DBSTRING=postgres://postgres:123456@localhost:5432/goose_test  
GOOSE_MIGRATION_DIR=./sql/schema

2. 创建 schema

执行下面的命令来创建一个迁移的 sql 文件

zsh 复制代码
goose create create_user_table sql

如下图所示,可以看到在项目的 sql/schema 目录当中创建一个 sql 文件。

在 sql 文件当中写入如下的内容。

sql 复制代码
-- +goose Up  
-- +goose StatementBegin  
CREATE TABLE IF NOT EXISTS account  
(  
    id       SERIAL PRIMARY KEY,  
    name     VARCHAR(255) NOT NULL,  
    email    VARCHAR(255) NOT NULL,  
    password VARCHAR(255) NOT NULL  
);  
-- +goose StatementEnd  
  
-- +goose Down  
-- +goose StatementBegin  
DROP TABLE IF EXISTS account;  
-- +goose StatementEnd

文件当中的 -- +goose Up 下面的部分是在执行 goose up 让数据库的版本 +1 的时候生效;-- +goose Down 下面的部分对应的上面部分的反向操作。上面的 sql goose up 的部分就是在数据库当中创建一张 account 表,而 goose down 的部分就是把数据当中的 account 表删掉。

3. 执行迁移

有了数据库迁移文件之后就可以开始执行数据库迁移了。常用的命令有下面两个:

  • goose up : 这个命令能够把当前数据库的版本升级到最新版本,也就是你最新创建的那个数据库迁移文件的版本。
  • goose down:这个命令会将当前的数据库版本进行降低,每次执行都降低一个版本。

更多的详细命令可以直接使用 goose 命令来查看详情。

下图使用一次 goose up 把最新的两次 sql 迁移文件都应用到数据当中,随后使用两次 goose down 把数据库的版本恢复到最开始版本。

20251125133155_create_post_table.sql 的内容如下:

sql 复制代码
-- +goose Up  
-- +goose StatementBegin  
CREATE TABLE IF NOT EXISTS post  
(  
    id       SERIAL PRIMARY KEY,  
    title    text NOT NULL,  
    body     text  
);  
-- +goose StatementEnd  
  
-- +goose Down  
-- +goose StatementBegin  
DROP TABLE IF EXISTS post;  
-- +goose StatementEnd

sqlc

sqlc 是一个为 Go 语言设计的 SQL 编译器,它能够从 SQL 查询生成完全类型安全的惯用 Go 代码。它不是一个 ORM,而是一个代码生成工具,专门解决数据库交互中的类型安全问题。

docs.sqlc.dev/en/stable/o...

安装

sqlc 本质是一个可执行程序,使用下面的命令来安装。

zsh 复制代码
go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest

配置

安装好了之后,就能够直接在命令行使用 sqlc 的命令。在项目当中使用我们需要先在项目的根目录下创建一个 sqlc.yaml 或者 sqlc.yml 的配置文件。sqlc 在生成代码的时候会自动读取配置文件当中的配置。

这里我使用的是 postgresql , 也可以使用 sqlc init 来自动创建配置文件,我这里的配置文件如下所示。

yaml 复制代码
version: "2"  
sql:  
  - engine: "postgresql"  
    queries: "sql/queries"  
    schema: "sql/schema"  
    gen:  
      go:  
        package: "db"  
        out: "db"  
        sql_package: "pgx/v5"

配置文件当中的 queries 配置了我需要使用的 SQL 语句所在的目录,schema 配置了数据库表结构,可以直接使用 goose 的 schema 。

gen 相关的配置就是配置生成的代码的一些信息,package 指定生成代码的包名,out 指定生成代码的文件夹, sql_package 指定生成的代码文件使用的数据库包。

编写 SQL

配置好了之后,就可以开始写自己的业务代码需要用到的 SQL 了,和配置文件指定的一样,把业务需要用到的 SQL 文件都写到 sql/queries 里面,创建一个 user.sql

这里我直接给出一个增、删、改、查的示例。

sql 复制代码
-- name: GetAccountById :one  
SELECT *  
FROM account  
WHERE id = $1 LIMIT 1;  
  
-- name: CreateUser :one  
INSERT INTO account (name, email, password)  
VALUES ($1, $2, $3) RETURNING *;  
  
-- name: UpdateUser :exec  
UPDATE account  
SET name = $1, email = $2, password = $3  
WHERE id = $4;  
  
-- name: DeleteUser :exec  
DELETE FROM account  
WHERE id = $1;

每个 SQL 开始之前的注释当中的 name 代表生成的代码当中的方法名,后面的 :one 代表返回一条记录,也可以是多条 :many ,也可以什么也不返回 :exec 。具体的使用可以参照详细的官方文档。

生成代码

接着就是使用 sqlc 来帮我们生成和数据库交互的相关代码。

直接在项目的根目录下执行 sqlc generate 即可,如下图所示,成功的在项目下的 db 文件夹生成了一些代码。

接下来就愉快的在自己的项目当中使用吧!这里我贴出这个调用上面的 user.sql 的调用示例。

go 复制代码
package main  
  
import (  
    "context"  
    "fmt"  
    "github.com/dimplesY/goose_test/db"    "github.com/jackc/pgx/v5")  
  
func main() {  
  
    conn, _ := pgx.Connect(context.Background(), "postgres://postgres:123456@localhost:5432/goose_test")  
    defer conn.Close(context.Background())  
    queries := db.New(conn)  
  
    user, _ := queries.CreateUser(context.Background(), db.CreateUserParams{  
       Name:     "1",  
       Email:    "1",  
       Password: "1",  
    })  
  
    fmt.Println(user)  
  
    u1, _ := queries.GetAccountById(context.Background(), user.ID)  
    fmt.Println(u1)  
  
    _ = queries.UpdateUser(context.Background(), db.UpdateUserParams{  
       Name:     "2",  
       Email:    "2",  
       Password: "2",  
       ID:       user.ID,  
    })  
  
    u2, _ := queries.GetAccountById(context.Background(), user.ID)  
    fmt.Println(u2)  
  
    _ = queries.DeleteUser(context.Background(), user.ID)  
  
    u3, _ := queries.GetAccountById(context.Background(), user.ID)  
    fmt.Println(u3)  
  
}

运行结构如下图所示:

相关推荐
万少2 小时前
我是如何使用 Trae IDE 完成《流碧卡片》项目的完整记录
前端·后端·ai编程
ituff2 小时前
微软认证考试又免费了
后端·python·flask
倔强的石头_3 小时前
openGauss赋能智能客服:AI时代的企业服务变革
后端
自不量力的A同学3 小时前
Spring Boot 4.0.0 正式发布
java·spring boot·后端
喵个咪3 小时前
go-kratos-admin 技术栈深度解析:为什么选 Golang+Vue3 这套组合?
vue.js·go
d***29243 小时前
【spring】Spring事件监听器ApplicationListener的使用与源码分析
java·后端·spring
v***5654 小时前
Spring Cloud Gateway 整合Spring Security
java·后端·spring
码事漫谈4 小时前
C++中不同类型的默认转换详解
后端
码事漫谈4 小时前
C++类型转换的隐蔽陷阱:当size_t遇见负数
后端