最佳实践
下面是基于 Flyway 的**生产级迁移脚本最佳实践指南**,专门针对你正在开发的 **Colleen Kotlin Web 框架** 和 PostgreSQL / JDBC 场景,总结自 Spring Boot、Rails、Laravel 等成熟框架的经验。
我会从:**命名 → 原子性 → 安全性 → 可维护性 → 团队协作 → 生产安全 → 反模式** 全面讲解。
---
# 一、文件命名最佳实践(极其重要)
Flyway 标准格式:
```text
V<version>__<description>.sql
```
示例:
```text
V1__init.sql
V2__create_users_table.sql
V3__add_email_to_users.sql
V4__create_index_on_users_email.sql
```
---
## 推荐 version 格式
推荐:
```text
V1
V2
V3
```
或:
```text
V001
V002
V003
```
或团队开发推荐:
```text
V20260227_001__init.sql
```
优点:
* 避免 merge 冲突
* 保证顺序
推荐用于 Colleen:
```text
V20260227_001__create_users.sql
```
---
## description 最佳实践
使用:
```text
snake_case
```
推荐:
```text
create_users_table
add_index_to_users_email
```
避免:
```text
createUsers
users
update
```
---
# 二、每个 migration 只做一件事(最重要原则)
正确:
```sql
-- V2__create_users_table.sql
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
email TEXT NOT NULL
);
```
错误:
```sql
CREATE TABLE users (...);
CREATE TABLE orders (...);
CREATE INDEX ...
ALTER TABLE ...
```
原因:
migration 必须:
* 可追踪
* 可回滚(逻辑上)
* 易排错
---
# 三、migration 必须是不可变的(绝对禁止修改旧 migration)
错误做法:
修改:
```text
V1__init.sql
```
正确做法:
新增:
```text
V2__add_column.sql
```
原因:
Flyway 使用 checksum 检测修改。
修改旧 migration 会导致:
```
Validate failed: checksum mismatch
```
生产环境会阻止启动。
---
# 四、永远使用 forward-only migration(最佳实践)
不要写:
```sql
DROP TABLE users;
```
而是:
```sql
ALTER TABLE users ADD COLUMN deleted BOOLEAN DEFAULT false;
```
原因:
drop 是 destructive。
production 不可恢复。
---
# 五、必须使用 IF NOT EXISTS(增强安全性)
推荐:
```sql
CREATE TABLE IF NOT EXISTS users (
id BIGSERIAL PRIMARY KEY
);
```
推荐:
```sql
CREATE INDEX IF NOT EXISTS idx_users_email
ON users(email);
```
避免:
```sql
CREATE TABLE users (...)
```
原因:
防止:
```
relation already exists
```
---
# 六、永远为 index 命名
正确:
```sql
CREATE INDEX idx_users_email
ON users(email);
```
错误:
```sql
CREATE INDEX ON users(email);
```
原因:
方便:
* 删除
* 调试
* 维护
---
# 七、永远为 constraint 命名
正确:
```sql
ALTER TABLE users
ADD CONSTRAINT users_email_unique UNIQUE(email);
```
错误:
```sql
ALTER TABLE users
ADD UNIQUE(email);
```
---
# 八、避免 destructive migration(生产级关键原则)
避免:
```sql
DROP COLUMN email;
```
推荐:
```sql
ALTER TABLE users
ADD COLUMN email_new TEXT;
```
然后:
应用层迁移数据。
最后:
```sql
ALTER TABLE users DROP COLUMN email;
```
分多个 migration。
---
# 九、大表 migration 必须考虑锁问题(Postgres 特别重要)
危险:
```sql
ALTER TABLE users ADD COLUMN email TEXT NOT NULL;
```
这会锁表。
推荐:
```sql
ALTER TABLE users ADD COLUMN email TEXT;
UPDATE users SET email = '';
ALTER TABLE users ALTER COLUMN email SET NOT NULL;
```
分三步 migration。
---
# 十、索引必须使用 CONCURRENTLY(Postgres)
危险:
```sql
CREATE INDEX idx_users_email ON users(email);
```
会锁表。
推荐:
```sql
CREATE INDEX CONCURRENTLY idx_users_email
ON users(email);
```
注意:
Flyway migration 必须设置:
```sql
-- flyway:executeInTransaction=false
```
因为 concurrently 不能在事务中执行。
完整:
```sql
-- flyway:executeInTransaction=false
CREATE INDEX CONCURRENTLY idx_users_email
ON users(email);
```
---
# 十一、migration 必须是幂等安全的(推荐)
推荐:
```sql
CREATE TABLE IF NOT EXISTS users (...)
```
不是:
```sql
CREATE TABLE users (...)
```
---
# 十二、永远把 schema migration 和 data migration 分开
不要:
```sql
ALTER TABLE users ADD COLUMN email TEXT;
UPDATE users SET email = 'test@test.com';
```
推荐:
```text
V2__add_email_column.sql
V3__fill_email.sql
```
原因:
便于排错。
---
# 十三、不要在 migration 中依赖应用代码
错误:
```sql
INSERT INTO users VALUES (generate_uuid());
```
除非保证 DB function 存在。
migration 必须:
自包含。
---
# 十四、推荐 Colleen migration 目录结构
```text
resources/
db/
migration/
V001__init.sql
V002__create_users.sql
V003__add_email.sql
V004__add_index.sql
```
---
# 十五、推荐 migration 示例(生产级)
```sql
-- V001__init.sql
CREATE TABLE IF NOT EXISTS users (
id BIGSERIAL PRIMARY KEY,
email TEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
```
---
```sql
-- V002__add_index_to_users_email.sql
-- flyway:executeInTransaction=false
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_users_email
ON users(email);
```
---
# 十六、团队协作最佳实践(极重要)
永远:
* 新增 migration
* 不修改旧 migration
正确:
```text
V1
V2
V3
```
错误:
```text
修改 V1
```
---
# 十七、生产环境绝对禁止使用 clean
永远:
```kotlin
.cleanDisabled(true)
```
clean 会删除所有表。
---
# 十八、Colleen 框架推荐 migration 配置
```kotlin
Flyway.configure()
.locations("classpath:db/migration")
.baselineOnMigrate(true)
.baselineVersion("0")
.validateOnMigrate(true)
.cleanDisabled(true)
.outOfOrder(false)
```
---
# 十九、最推荐 version 命名(Colleen 官方推荐)
```text
V20260227_001__create_users.sql
V20260227_002__add_email.sql
```
优点:
* 无冲突
* 可排序
* 可读性强
---
# 二十、最常见灾难级错误(必须避免)
修改旧 migration:
```text
V1__init.sql ← 修改它
```
正确:
```text
V2__fix.sql
```
---
# 二十一、总结(最重要 8 条)
必须遵守:
1. 永远不要修改旧 migration
2. 每个 migration 只做一件事
3. 使用 IF NOT EXISTS
4. 使用明确命名
5. forward-only migration
6. 使用 CONCURRENTLY 创建 index
7. migration 必须可重复执行(安全)
8. migration 必须可追踪
---
如果你愿意,我可以提供一个:
**Colleen 官方推荐 migration 模板**
包括:
* table
* index
* constraint
* trigger
* enum
完整生产级示例。