数据库迁移
This commit is contained in:
@@ -32,6 +32,7 @@ Keep this managed block so 'openspec update' can refresh the instructions.
|
|||||||
- 日志消息必须使用中文
|
- 日志消息必须使用中文
|
||||||
- 用户可见的错误消息必须使用中文
|
- 用户可见的错误消息必须使用中文
|
||||||
- 变量名、函数名、类型名必须使用英文(遵循 Go 命名规范)
|
- 变量名、函数名、类型名必须使用英文(遵循 Go 命名规范)
|
||||||
|
- GIT提交的commit必须使用中文
|
||||||
|
|
||||||
## 技术栈
|
## 技术栈
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,19 @@
|
|||||||
-- 000003_add_owner_id_shop_id.down.sql
|
-- 000003_add_owner_id_shop_id.down.sql
|
||||||
-- 示例迁移:回滚 owner_id 和 shop_id 字段
|
-- 重要说明:user/order 模块已移除,本模板仅供新的业务表参照。
|
||||||
-- 注:此为模板迁移,实际业务表由项目需求决定
|
|
||||||
|
|
||||||
-- 示例:回滚订单表的数据权限字段
|
-- 示例:回滚 SIM 卡表的数据权限字段
|
||||||
-- DROP INDEX IF EXISTS idx_orders_owner_shop;
|
-- DROP INDEX IF EXISTS idx_sim_card_owner_shop;
|
||||||
-- DROP INDEX IF EXISTS idx_orders_shop_id;
|
-- DROP INDEX IF EXISTS idx_sim_card_shop_id;
|
||||||
-- DROP INDEX IF EXISTS idx_orders_owner_id;
|
-- DROP INDEX IF EXISTS idx_sim_card_owner_id;
|
||||||
-- ALTER TABLE tb_orders DROP COLUMN IF EXISTS shop_id;
|
-- ALTER TABLE tb_sim_card DROP COLUMN IF EXISTS shop_id;
|
||||||
-- ALTER TABLE tb_orders DROP COLUMN IF EXISTS owner_id;
|
-- ALTER TABLE tb_sim_card DROP COLUMN IF EXISTS owner_id;
|
||||||
|
|
||||||
-- 示例:回滚商品表的数据权限字段
|
-- 示例:回滚设备表的数据权限字段
|
||||||
-- DROP INDEX IF EXISTS idx_products_owner_shop;
|
-- DROP INDEX IF EXISTS idx_device_owner_shop;
|
||||||
-- DROP INDEX IF EXISTS idx_products_shop_id;
|
-- DROP INDEX IF EXISTS idx_device_shop_id;
|
||||||
-- DROP INDEX IF EXISTS idx_products_owner_id;
|
-- DROP INDEX IF EXISTS idx_device_owner_id;
|
||||||
-- ALTER TABLE tb_products DROP COLUMN IF EXISTS shop_id;
|
-- ALTER TABLE tb_device DROP COLUMN IF EXISTS shop_id;
|
||||||
-- ALTER TABLE tb_products DROP COLUMN IF EXISTS owner_id;
|
-- ALTER TABLE tb_device DROP COLUMN IF EXISTS owner_id;
|
||||||
|
|
||||||
-- 占位语句(避免空迁移文件报错)
|
-- 占位语句(避免空迁移文件报错)
|
||||||
SELECT 1;
|
SELECT 1;
|
||||||
|
|||||||
@@ -1,27 +1,28 @@
|
|||||||
-- 000003_add_owner_id_shop_id.up.sql
|
-- 000003_add_owner_id_shop_id.up.sql
|
||||||
-- 示例迁移:为业务表添加 owner_id 和 shop_id 字段
|
|
||||||
-- 注:此为模板迁移,实际业务表由项目需求决定
|
-- 重要说明:user/order 模块已移除,本模板仅供新的业务表(例如 SIM、设备、套餐等)参照。
|
||||||
-- 使用方法:
|
-- 使用方法:
|
||||||
-- 1. 复制此模板
|
-- 1. 复制此模板
|
||||||
-- 2. 修改表名为实际业务表
|
-- 2. 替换示例表名为真实表名
|
||||||
-- 3. 根据业务需求调整字段类型和约束
|
-- 3. 按需调整字段类型、索引、默认值
|
||||||
|
|
||||||
-- 示例:为订单表添加数据权限字段
|
-- 示例:为 SIM 卡表添加数据权限字段
|
||||||
-- ALTER TABLE tb_orders ADD COLUMN owner_id BIGINT;
|
-- ALTER TABLE tb_sim_card ADD COLUMN owner_id BIGINT;
|
||||||
-- ALTER TABLE tb_orders ADD COLUMN shop_id BIGINT;
|
-- ALTER TABLE tb_sim_card ADD COLUMN shop_id BIGINT;
|
||||||
--
|
--
|
||||||
-- -- 创建索引以支持数据权限过滤
|
-- CREATE INDEX idx_sim_card_owner_id ON tb_sim_card(owner_id) WHERE deleted_at IS NULL;
|
||||||
-- CREATE INDEX idx_orders_owner_id ON tb_orders(owner_id) WHERE deleted_at IS NULL;
|
-- CREATE INDEX idx_sim_card_shop_id ON tb_sim_card(shop_id) WHERE deleted_at IS NULL;
|
||||||
-- CREATE INDEX idx_orders_shop_id ON tb_orders(shop_id) WHERE deleted_at IS NULL;
|
-- CREATE INDEX idx_sim_card_owner_shop ON tb_sim_card(owner_id, shop_id) WHERE deleted_at IS NULL;
|
||||||
-- CREATE INDEX idx_orders_owner_shop ON tb_orders(owner_id, shop_id) WHERE deleted_at IS NULL;
|
|
||||||
|
|
||||||
-- 示例:为商品表添加数据权限字段
|
-- 示例:为设备表添加数据权限字段
|
||||||
-- ALTER TABLE tb_products ADD COLUMN owner_id BIGINT;
|
-- ALTER TABLE tb_device ADD COLUMN owner_id BIGINT;
|
||||||
-- ALTER TABLE tb_products ADD COLUMN shop_id BIGINT;
|
-- ALTER TABLE tb_device ADD COLUMN shop_id BIGINT;
|
||||||
--
|
--
|
||||||
-- CREATE INDEX idx_products_owner_id ON tb_products(owner_id) WHERE deleted_at IS NULL;
|
-- CREATE INDEX idx_device_owner_id ON tb_device(owner_id) WHERE deleted_at IS NULL;
|
||||||
-- CREATE INDEX idx_products_shop_id ON tb_products(shop_id) WHERE deleted_at IS NULL;
|
-- CREATE INDEX idx_device_shop_id ON tb_device(shop_id) WHERE deleted_at IS NULL;
|
||||||
-- CREATE INDEX idx_products_owner_shop ON tb_products(owner_id, shop_id) WHERE deleted_at IS NULL;
|
-- CREATE INDEX idx_device_owner_shop ON tb_device(owner_id, shop_id) WHERE deleted_at IS NULL;
|
||||||
|
|
||||||
|
-- 批量表处理建议:可将多个 ALTER 语句放入同一次迁移,以保持版本一致。
|
||||||
|
|
||||||
-- 通用数据权限字段规范:
|
-- 通用数据权限字段规范:
|
||||||
-- owner_id: 数据所有者账号 ID,关联 tb_account.id
|
-- owner_id: 数据所有者账号 ID,关联 tb_account.id
|
||||||
|
|||||||
83
migrations/000004_drop_legacy_user_order.down.sql
Normal file
83
migrations/000004_drop_legacy_user_order.down.sql
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
-- 000004_drop_legacy_user_order.down.sql
|
||||||
|
-- 说明:回滚时恢复 legacy 用户/订单表(与历史 000001_init_schema 一致)。
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
-- 恢复用户表
|
||||||
|
CREATE TABLE IF NOT EXISTS tb_user (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
|
||||||
|
-- 基本信息
|
||||||
|
username VARCHAR(50) NOT NULL,
|
||||||
|
email VARCHAR(100) NOT NULL,
|
||||||
|
password VARCHAR(255) NOT NULL,
|
||||||
|
|
||||||
|
-- 状态字段
|
||||||
|
status VARCHAR(20) NOT NULL DEFAULT 'active',
|
||||||
|
|
||||||
|
-- 元数据
|
||||||
|
last_login_at TIMESTAMP,
|
||||||
|
|
||||||
|
-- 唯一约束
|
||||||
|
CONSTRAINT uk_user_username UNIQUE (username),
|
||||||
|
CONSTRAINT uk_user_email UNIQUE (email)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 恢复订单表
|
||||||
|
CREATE TABLE IF NOT EXISTS tb_order (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
|
||||||
|
-- 业务唯一键
|
||||||
|
order_id VARCHAR(50) NOT NULL,
|
||||||
|
|
||||||
|
-- 关联关系(注意:无数据库外键约束,在代码中管理)
|
||||||
|
user_id INTEGER NOT NULL,
|
||||||
|
|
||||||
|
-- 订单信息
|
||||||
|
amount BIGINT NOT NULL,
|
||||||
|
status VARCHAR(20) NOT NULL DEFAULT 'pending',
|
||||||
|
remark VARCHAR(500),
|
||||||
|
|
||||||
|
-- 时间字段
|
||||||
|
paid_at TIMESTAMP,
|
||||||
|
completed_at TIMESTAMP,
|
||||||
|
|
||||||
|
-- 唯一约束
|
||||||
|
CONSTRAINT uk_order_order_id UNIQUE (order_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 索引恢复
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_user_deleted_at ON tb_user(deleted_at);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_user_status ON tb_user(status);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_user_created_at ON tb_user(created_at);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_order_deleted_at ON tb_order(deleted_at);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_order_user_id ON tb_order(user_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_order_status ON tb_order(status);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_order_created_at ON tb_order(created_at);
|
||||||
|
|
||||||
|
-- 注释恢复
|
||||||
|
COMMENT ON TABLE tb_user IS '用户表';
|
||||||
|
COMMENT ON COLUMN tb_user.username IS '用户名(唯一)';
|
||||||
|
COMMENT ON COLUMN tb_user.email IS '邮箱(唯一)';
|
||||||
|
COMMENT ON COLUMN tb_user.password IS '密码(bcrypt 哈希)';
|
||||||
|
COMMENT ON COLUMN tb_user.status IS '用户状态:active, inactive, suspended';
|
||||||
|
COMMENT ON COLUMN tb_user.deleted_at IS '软删除时间';
|
||||||
|
|
||||||
|
COMMENT ON TABLE tb_order IS '订单表';
|
||||||
|
COMMENT ON COLUMN tb_order.order_id IS '订单号(业务唯一键)';
|
||||||
|
COMMENT ON COLUMN tb_order.user_id IS '用户 ID(在代码中维护关联,无数据库外键)';
|
||||||
|
COMMENT ON COLUMN tb_order.amount IS '金额(分)';
|
||||||
|
COMMENT ON COLUMN tb_order.status IS '订单状态:pending, paid, processing, completed, cancelled';
|
||||||
|
COMMENT ON COLUMN tb_order.deleted_at IS '软删除时间';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- 占位,避免空事务报错
|
||||||
|
SELECT 1;
|
||||||
13
migrations/000004_drop_legacy_user_order.up.sql
Normal file
13
migrations/000004_drop_legacy_user_order.up.sql
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
-- 000004_drop_legacy_user_order.up.sql
|
||||||
|
-- 说明:清理已废弃的 legacy 用户/订单表,保证数据库结构与现有代码一致。
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
-- 先删除依赖度更高的订单表,再删除用户表
|
||||||
|
DROP TABLE IF EXISTS tb_order;
|
||||||
|
DROP TABLE IF EXISTS tb_user;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- 占位,避免空事务报错
|
||||||
|
SELECT 1;
|
||||||
@@ -38,11 +38,12 @@ show_usage() {
|
|||||||
用法: $0 [命令] [参数]
|
用法: $0 [命令] [参数]
|
||||||
|
|
||||||
命令:
|
命令:
|
||||||
up [N] 向上迁移 N 步 (默认: 全部)
|
up [N] 向上迁移 N 步 (默认: 全部,完成后自动检查 legacy 表)
|
||||||
down [N] 向下回滚 N 步 (默认: 1)
|
down [N] 向下回滚 N 步 (默认: 1)
|
||||||
create NAME 创建新的迁移文件
|
create NAME 创建新的迁移文件
|
||||||
version 显示当前迁移版本
|
version 显示当前迁移版本
|
||||||
force V 强制设置迁移版本为 V (用于修复脏数据库状态)
|
force V 强制设置迁移版本为 V (用于修复脏数据库状态)
|
||||||
|
check-legacy 检查 legacy 表 (tb_user/tb_order) 是否仍存在
|
||||||
help 显示此帮助信息
|
help 显示此帮助信息
|
||||||
|
|
||||||
环境变量:
|
环境变量:
|
||||||
@@ -59,10 +60,36 @@ show_usage() {
|
|||||||
$0 create add_sim_table # 创建新迁移文件
|
$0 create add_sim_table # 创建新迁移文件
|
||||||
$0 version # 查看当前版本
|
$0 version # 查看当前版本
|
||||||
$0 force 1 # 强制设置版本为 1
|
$0 force 1 # 强制设置版本为 1
|
||||||
|
$0 check-legacy # 单独检查 tb_user/tb_order 是否存在
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_legacy_tables() {
|
||||||
|
if ! command -v psql &> /dev/null; then
|
||||||
|
echo "提示: 未检测到 psql 命令,跳过 legacy 表检查"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "正在检查 legacy 表 tb_user / tb_order..."
|
||||||
|
if ! CHECK_RESULT=$(psql "$DATABASE_URL" -Atqc "SELECT table_name FROM information_schema.tables WHERE table_schema='public' AND table_name IN ('tb_user','tb_order');"); then
|
||||||
|
echo "警告: 无法执行 legacy 表检查,请手动确认"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$CHECK_RESULT" ]; then
|
||||||
|
echo "✓ 未发现 legacy 表,数据库结构已与代码同步"
|
||||||
|
else
|
||||||
|
echo "⚠ 检测到以下 legacy 表仍然存在:"
|
||||||
|
echo "$CHECK_RESULT" | while read -r table_name; do
|
||||||
|
if [ -n "$table_name" ]; then
|
||||||
|
printf ' - %s\n' "$table_name"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "请确保已经执行 000004_drop_legacy_user_order 迁移或手动清理上述表"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# 主命令处理
|
# 主命令处理
|
||||||
case "$1" in
|
case "$1" in
|
||||||
up)
|
up)
|
||||||
@@ -73,6 +100,8 @@ case "$1" in
|
|||||||
echo "正在向上迁移 $2 步..."
|
echo "正在向上迁移 $2 步..."
|
||||||
migrate -path "$MIGRATIONS_DIR" -database "$DATABASE_URL" up "$2"
|
migrate -path "$MIGRATIONS_DIR" -database "$DATABASE_URL" up "$2"
|
||||||
fi
|
fi
|
||||||
|
echo "迁移完成,开始检查 legacy 表..."
|
||||||
|
check_legacy_tables
|
||||||
;;
|
;;
|
||||||
down)
|
down)
|
||||||
STEPS="${2:-1}"
|
STEPS="${2:-1}"
|
||||||
@@ -103,6 +132,9 @@ case "$1" in
|
|||||||
echo "强制设置迁移版本为: $2"
|
echo "强制设置迁移版本为: $2"
|
||||||
migrate -path "$MIGRATIONS_DIR" -database "$DATABASE_URL" force "$2"
|
migrate -path "$MIGRATIONS_DIR" -database "$DATABASE_URL" force "$2"
|
||||||
;;
|
;;
|
||||||
|
check-legacy)
|
||||||
|
check_legacy_tables
|
||||||
|
;;
|
||||||
help|--help|-h)
|
help|--help|-h)
|
||||||
show_usage
|
show_usage
|
||||||
;;
|
;;
|
||||||
|
|||||||
Reference in New Issue
Block a user