docs(goose): 添加数据库迁移使用笔记
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
# Goose 数据库迁移笔记
|
||||
|
||||
Goose 用迁移文件管理数据库结构变更,并在数据库中记录已执行的迁移版本。
|
||||
|
||||
本文以 **PostgreSQL、Goose v3.29.0** 为例,命令使用 Bash 语法。
|
||||
|
||||
## 1. 基本概念
|
||||
|
||||
- **迁移文件**:按版本组织的数据库变更脚本。
|
||||
- **Up**:应用变更,例如建表、增加字段。
|
||||
- **Down**:撤销对应变更;能否恢复数据取决于具体 SQL。
|
||||
- **版本记录**:Goose 默认通过 `goose_db_version` 表跟踪迁移状态。
|
||||
- **工具版本与迁移版本不同**:`goose -version` 查看工具版本,`goose version` 查看数据库迁移版本。
|
||||
|
||||
通常将迁移文件放在 `migrations/` 目录。下文命令在该目录的上一级执行,目标数据库需事先创建。
|
||||
|
||||
## 2. 安装
|
||||
|
||||
需要先安装 Go,再安装指定版本的 Goose CLI:
|
||||
|
||||
```bash
|
||||
go install github.com/pressly/goose/v3/cmd/goose@v3.29.0
|
||||
goose -version
|
||||
```
|
||||
|
||||
固定工具版本有助于保持不同环境的行为一致。Goose 可以作为独立命令行工具使用。
|
||||
|
||||
默认安装位置是 `$(go env GOPATH)/bin`;若设置了 `GOBIN`,则安装到该目录。找不到命令时,将实际安装目录加入 `PATH`:
|
||||
|
||||
```bash
|
||||
# 未设置 GOBIN 时
|
||||
export PATH="$PATH:$(go env GOPATH)/bin"
|
||||
```
|
||||
|
||||
## 3. 配置数据库连接
|
||||
|
||||
在工作目录创建 `.env.local`,填写连接配置:
|
||||
|
||||
```dotenv
|
||||
GOOSE_DRIVER=postgres
|
||||
GOOSE_MIGRATION_DIR=./migrations
|
||||
GOOSE_DBSTRING="postgres://example_user:URL_ENCODED_PASSWORD@127.0.0.1:5432/example_db?sslmode=disable"
|
||||
```
|
||||
|
||||
以上用户名、密码和数据库名都是占位值,地址与端口也需按实际环境填写。
|
||||
|
||||
- `GOOSE_DRIVER`:数据库驱动;连接 PostgreSQL 时使用 `postgres`。
|
||||
- `GOOSE_MIGRATION_DIR`:迁移文件目录。
|
||||
- `GOOSE_DBSTRING`:数据库连接串。Goose 不会自动从应用配置文件或零散的应用环境变量中拼装它。
|
||||
- Goose 默认读取 `.env`;本文统一使用 `-env=.env.local` 显式指定配置文件。
|
||||
- `sslmode=disable` 适用于本地无 TLS 要求的场景;其他环境按实际 TLS 要求配置。
|
||||
|
||||
将含凭据的配置文件加入版本控制忽略规则。类 Unix 系统还可限制文件权限:
|
||||
|
||||
```bash
|
||||
chmod 600 .env.local
|
||||
```
|
||||
|
||||
系统中已有的同名环境变量可能优先于配置文件生效。修改文件后连接行为未改变时,可只列出相关变量名排查,避免打印连接串:
|
||||
|
||||
```bash
|
||||
env | cut -d= -f1 | grep -i '^GOOSE'
|
||||
```
|
||||
|
||||
## 4. 连接串中的 URL 编码
|
||||
|
||||
使用 URL 格式的连接串时,用户名、密码中的特殊字符需要进行百分号编码。
|
||||
|
||||
| 字符 | 编码 | 字符 | 编码 |
|
||||
|---|---|---|---|
|
||||
| `@` | `%40` | `:` | `%3A` |
|
||||
| `#` | `%23` | `/` | `%2F` |
|
||||
| `%` | `%25` | `?` | `%3F` |
|
||||
|
||||
例如,演示密码 `demo#pass` 在连接串中写成 `demo%23pass`。
|
||||
|
||||
- 分别编码用户名和密码,不要编码整个 URL。
|
||||
- 避免对已编码的内容重复编码。
|
||||
- 编码只改变连接串的写法,不改变数据库中的实际密码。
|
||||
- 不要将真实密码提交给在线编码网站。
|
||||
|
||||
## 5. 常用命令
|
||||
|
||||
```bash
|
||||
# 查看 Goose 工具版本
|
||||
goose -version
|
||||
|
||||
# 离线检查迁移文件是否能被解析
|
||||
goose -env=.env.local validate
|
||||
|
||||
# 查看迁移状态与数据库当前迁移版本
|
||||
goose -env=.env.local status
|
||||
goose -env=.env.local version
|
||||
|
||||
# 应用尚未执行的迁移
|
||||
goose -env=.env.local up
|
||||
|
||||
# 回滚最近一个已应用的迁移;执行前检查对应 Down SQL
|
||||
goose -env=.env.local down
|
||||
```
|
||||
|
||||
`validate` 检查注解与语句拆分,不连接数据库,也不验证 SQL 在 PostgreSQL 上的语义。校验通过不代表数据库连接正常或迁移一定执行成功。
|
||||
|
||||
在 v3.29.0 中,`validate` 不接受位置路径参数。迁移目录通过 `GOOSE_MIGRATION_DIR` 或 `-dir` 指定:
|
||||
|
||||
```bash
|
||||
goose -env=.env.local -dir=./migrations validate
|
||||
```
|
||||
|
||||
## 6. 创建与执行迁移
|
||||
|
||||
### 创建迁移文件
|
||||
|
||||
```bash
|
||||
goose -env=.env.local -s create create_example_items sql
|
||||
```
|
||||
|
||||
`-s` 表示使用顺序编号,版本号按目录中已有迁移延续。例如,目录为空时,首个文件可命名为:
|
||||
|
||||
```text
|
||||
migrations/00001_create_example_items.sql
|
||||
```
|
||||
|
||||
### 编写 Up 与 Down
|
||||
|
||||
下面用一张示例表演示迁移结构:
|
||||
|
||||
```sql
|
||||
-- +goose Up
|
||||
CREATE TABLE public.example_items (
|
||||
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||
name text NOT NULL
|
||||
);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE public.example_items;
|
||||
```
|
||||
|
||||
该示例的 Down 会删除表及其中的数据。
|
||||
|
||||
### 检查并执行
|
||||
|
||||
```bash
|
||||
goose -env=.env.local validate
|
||||
goose -env=.env.local status
|
||||
goose -env=.env.local up
|
||||
goose -env=.env.local status
|
||||
goose -env=.env.local version
|
||||
```
|
||||
|
||||
执行前确认目标数据库已创建,且待创建的对象不存在。`status` 中的 `Pending` 表示对应迁移尚未应用。
|
||||
|
||||
Goose 会记录成功应用的迁移;再次执行 `up` 时,已应用版本会被跳过。
|
||||
|
||||
## 7. 变更与回滚原则
|
||||
|
||||
- **已执行的迁移文件不再修改**;后续结构变更通过新增迁移实现。
|
||||
- 为需要回滚的迁移编写对应 Down,并检查它能否正确撤销结构变更。
|
||||
- `down` 只回滚最近一个已应用迁移,不是清库或重建数据库的通用命令。
|
||||
- 删除表或字段可能丢失数据;反向 SQL 不等于数据恢复。
|
||||
- 回滚前阅读对应 SQL、评估影响并备份数据库。
|
||||
- 避免手工执行与迁移文件重复的建表脚本,以免对象和版本记录不一致。
|
||||
|
||||
## 8. 常见问题
|
||||
|
||||
| 报错或现象 | 排查方向 |
|
||||
|---|---|
|
||||
| 找不到 `goose` 命令 | 检查安装是否成功,以及实际安装目录是否已加入 `PATH` |
|
||||
| `hostname resolving error`,主机名混入非法字符 | 检查连接串分隔符,以及用户名、密码的 URL 编码 |
|
||||
| `password authentication failed` | 核对用户名、密码及编码;检查系统同名环境变量是否覆盖配置 |
|
||||
| `connection refused` / `i/o timeout` | 检查监听地址、端口、容器端口映射和防火墙 |
|
||||
| `already exists` | 检查对象是否已被手工创建;先比较现有结构与迁移内容,再确定处理方式 |
|
||||
| 修改 `.env.local` 后配置似乎未生效 | 确认使用了 `-env=.env.local`,并排查系统中已有的同名环境变量 |
|
||||
|
||||
遇到对象已存在的问题,不要直接删除现有数据,也不要手工插入版本记录来伪造迁移状态。
|
||||
Reference in New Issue
Block a user