Files
agent-skills/skills/g3fo-db-ops/references/DATABASE_UPDATE_AUTOMATION_GUIDE.md
T

880 lines
30 KiB
Markdown
Raw Normal View History

2026-02-04 17:19:57 +08:00
# G3FO 数据库更新自动化流程指南
## 概述
本文档定义了使用 Cursor 更新 G3FO 项目数据库数据的标准自动化流程。当需要更新数据库时,系统会自动生成 SQL 语句文件并更新到 `g3fo-db` 仓库中。
## 目录结构
```
g3fo-db/
├── common_sql/ # 通用SQL模板和工具
│ ├── insert_system_route_procedure.sql # 插入系统路由存储过程
│ ├── create_table_template.sql # 创建表模板
│ ├── system_code_update_template.sql # 系统代码更新模板
│ ├── table_change_template.sql # 表结构变更模板
│ └── DATABASE_UPDATE_AUTOMATION_GUIDE.md # 本文档
└── update_service_release/ # 版本发布SQL文件夹
└── pending release {version}/ # 待执行SQL文件夹(最新版本)
```
## 一、使用现有模板和工具
### 1.1 插入系统菜单和路径权限
**重要规则:增加菜单和路径权限必须使用 `common_sql` 文件夹中的存储过程文件。**
**使用的文件:**
- `g3fo-db/common_sql/insert_system_menu_procedure.sql` - 插入系统菜单
- `g3fo-db/common_sql/insert_system_route_procedure.sql` - 插入系统路由
**执行和提交规则:**
#### 执行 SQL 阶段
由于 MySQL MCP 不支持使用 `DELIMITER` 的存储过程,执行时可以使用其他方法插入或更新相同的数据:
1. **使用直接的 INSERT/REPLACE 语句**:
- 使用 `INSERT INTO` 或 `REPLACE INTO` 语句直接插入数据
- 确保数据与存储过程生成的数据完全一致
- 需要手动处理 ID 生成、权限记录创建等逻辑
2. **数据一致性要求**:
- 菜单数据必须插入到 `m_system_menus` 表
- 路由数据必须插入到 `m_system_routes` 表
- 相应的权限记录必须插入到 `m_admin_role_rights` 或 `m_user_role_rights` 表
- 所有数据必须与存储过程生成的数据完全一致
#### 提交到 Git 阶段
**必须使用存储过程文件生成的完整 SQL:**
1. **从模板文件复制**:
- 从 `g3fo-db/common_sql/insert_system_menu_procedure.sql` 复制完整的存储过程定义
- 或从 `g3fo-db/common_sql/insert_system_route_procedure.sql` 复制完整的存储过程定义
2. **添加 CALL 语句**:
- 在文件末尾添加 `CALL` 语句来调用存储过程
- 参考 `update_service_release/pending release 1.5.1.18` 中的文件格式
3. **文件格式示例**:
**插入系统菜单:**
```sql
USE g3fo_base;
-- ===================================================================
-- 存储过程:插入系统菜单数据
-- ... (完整的存储过程定义,从 insert_system_menu_procedure.sql 复制) ...
-- ===================================================================
DROP PROCEDURE IF EXISTS InsertSystemMenu;
DELIMITER $$
CREATE PROCEDURE InsertSystemMenu(...)
BEGIN
-- ... 存储过程代码 ...
END$$
DELIMITER ;
-- ===================================================================
-- 在这里添加需要插入的菜单
-- ===================================================================
CALL InsertSystemMenu('菜单备注', 'menu-name', 'title_remark', 'ADMIN', NULL, 1);
CALL InsertSystemMenu('菜单备注2', 'menu-name-2', 'title_remark', 'USER', NULL, 1);
```
**插入系统路由:**
```sql
USE g3fo_base;
-- ===================================================================
-- 存储过程:插入系统路由数据
-- ... (完整的存储过程定义,从 insert_system_route_procedure.sql 复制) ...
-- ===================================================================
DROP PROCEDURE IF EXISTS InsertSystemRoute;
DELIMITER $$
CREATE PROCEDURE InsertSystemRoute(...)
BEGIN
-- ... 存储过程代码 ...
END$$
DELIMITER ;
-- ===================================================================
-- 在这里添加需要插入的路由
-- ===================================================================
CALL InsertSystemRoute('备注', '/route/path', '标题备注', 'ADMIN');
CALL InsertSystemRoute('备注2', '/route/path2', '标题备注', 'USER');
```
**文件命名规范:**
- 菜单:`insert_system_menu_procedure_{序号}.sql`
- 路由:`insert_system_route_procedure_{序号}.sql`
**参考示例:**
- 查看 `update_service_release/pending release 1.5.1.18/insert_system_menu_procedure_03.sql` 作为参考
**参数说明:**
**InsertSystemMenu 参数:**
- `p_remark`: 菜单备注(varchar(50))
- `p_menu_name`: 菜单名称,唯一标识(varchar(255))
- `p_title_remark`: 标题备注(varchar(50))
- `p_menu_type`: 菜单类型,'ADMIN' 或 'USER'(char(8))
- `p_description_i18n_id`: 描述国际化ID,可选(char(32)),默认为NULL
- `p_active_flag`: 激活标志,可选(smallint),默认为1
**InsertSystemRoute 参数:**
- `p_remark`: 备注
- `p_route`: 路由地址
- `p_title_remark`: 标题备注
- `p_route_type`: 路由类型('ADMIN' 或 'USER')
**功能:**
- 自动生成ID(菜单从1开始,路由从7000开始)
- 自动为相应角色模板创建权限记录
- 自动去重检查
### 1.2 创建新表
当需要创建新表时,参照 `create_table_template.sql` 中的格式:
- 使用 `CREATE TABLE IF NOT EXISTS`
- 指定正确的 schema(如 `g3fo_trade`, `g3fo_base` 等)
- 包含必要的字段、索引、注释
- 使用 `ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci`
### 1.3 表结构变更
当需要修改表结构时,参照 `table_change_template.sql` 中的方法:
- 使用存储过程检查列是否存在
- 使用 `IF EXISTS` 进行幂等性检查
- 执行后删除存储过程
### 1.4 订单表字段同步规则
**重要:当 `m_order` 表需要增加字段时,以下三个表必须同时增加相同的字段:**
1. `m_order_actions` - 订单操作表(g3fo_trade schema)
2. `h_order` - 订单历史表(g3fo_trade schema)
3. `h_order_actions` - 订单操作历史表(g3fo_trade schema)
**规则说明:**
- 字段名称必须完全一致
- 字段类型必须完全一致
- 字段约束(NULL/NOT NULL、DEFAULT 等)必须完全一致
- 字段注释必须完全一致
- 字段位置(AFTER 子句)应保持一致
**SQL 生成要求:**
- 使用存储过程进行幂等性检查(参照 `table_change_template.sql`)
- 为每个表分别检查字段是否存在,不存在则添加
- 确保所有四个表的字段变更在同一个 SQL 文件中完成
- 使用相同的存储过程模式,为每个表创建独立的检查逻辑
**SQL 模板示例:**
```sql
USE g3fo_trade;
DROP PROCEDURE IF EXISTS AddOrderField;
DELIMITER $$
CREATE PROCEDURE AddOrderField()
BEGIN
-- 为 m_order 表添加字段
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = 'g3fo_trade'
AND table_name = 'm_order'
AND column_name = 'new_field'
) THEN
ALTER TABLE `g3fo_trade`.`m_order`
ADD COLUMN `new_field` VARCHAR(100) NULL DEFAULT NULL COMMENT '新字段'
AFTER `existing_field`;
END IF;
-- 为 m_order_actions 表添加相同字段
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = 'g3fo_trade'
AND table_name = 'm_order_actions'
AND column_name = 'new_field'
) THEN
ALTER TABLE `g3fo_trade`.`m_order_actions`
ADD COLUMN `new_field` VARCHAR(100) NULL DEFAULT NULL COMMENT '新字段'
AFTER `existing_field`;
END IF;
-- 为 h_order 表添加相同字段
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = 'g3fo_trade'
AND table_name = 'h_order'
AND column_name = 'new_field'
) THEN
ALTER TABLE `g3fo_trade`.`h_order`
ADD COLUMN `new_field` VARCHAR(100) NULL DEFAULT NULL COMMENT '新字段'
AFTER `existing_field`;
END IF;
-- 为 h_order_actions 表添加相同字段
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = 'g3fo_trade'
AND table_name = 'h_order_actions'
AND column_name = 'new_field'
) THEN
ALTER TABLE `g3fo_trade`.`h_order_actions`
ADD COLUMN `new_field` VARCHAR(100) NULL DEFAULT NULL COMMENT '新字段'
AFTER `existing_field`;
END IF;
END$$
DELIMITER ;
CALL AddOrderField();
DROP PROCEDURE IF EXISTS AddOrderField;
```
**注意事项:**
- 所有四个表的字段定义必须完全一致
- 必须使用幂等性检查,确保 SQL 可以重复执行
- 字段位置(AFTER 子句)应保持一致,便于维护
## 二、需要同时更新 m_system_i18n 的表
以下表在更新数据时必须同时更新 `m_system_i18n` 表:
| 表名 | i18n_id 格式 | 填充值 | 说明 |
|------|-------------|--------|------|
| `m_system_code` | `CODE-{id}` | 4位数字ID(如 `CODE-0404`) | 系统编码表 |
| `m_system_error_message` | `ERR-{id}` | 错误码ID | 系统错误消息表 |
| `m_market` | `MKT-{id}` | 4位数字ID | 市场表 |
| `m_currency` | `CURR-{code}` | 货币代码 | 货币表 |
| `m_channel` | `CH-{code}` | 渠道代码 | 渠道表 |
| `m_exchange` | `EXCH-{code}` | 交易所代码 | 交易所表 |
| `m_country` | `CNTY-{code}` | 国家代码 | 国家表 |
| `m_exchange_charge` | `EX_CHARGE-{id}` | 费用ID | 交易所费用表 |
| `m_company_charge` | `COM_CHARGE-{id}` | 费用ID | 公司费用表 |
**重要:** 所有上述表的插入和更新操作都必须同时更新 `m_system_i18n` 表,以提供多语言支持。
## 三、自动化数据插入流程
### 3.1 流程概述
1. **用户输入数据** → 2. **生成SQL语句** → 3. **用户确认** → 4. **执行SQL** → 5. **确认执行结果** → 6. **询问是否提交到Git** → 7. **Git操作**
### 3.2 以 m_system_code 为例的详细流程
#### 步骤 1: 请求用户输入
当用户需要更新或增加 `m_system_code` 的数据时,Cursor 应请求以下信息:
```
请提供以下数据:
- Code_type: [编码类型]
- Code_value: [编码值]
- Remark: [备注(用于生成多语言描述)]
- Sort: [排序号]
```
#### 步骤 2: 自动生成SQL
Cursor 自动执行以下操作:
1. **获取当前最大ID**
```sql
SELECT COALESCE(MAX(id), 0) + 1 FROM g3fo_base.m_system_code;
```
2. **生成 description_i18n_id**
- 格式:`CODE-{4位数字ID}`
- 例如:ID=404 → `CODE-0404`
3. **根据 remark 生成多语言描述**
- 如果 remark 包含中英文,自动提取
- 如果没有,使用 remark 作为英文描述
- 简体中文(sc_description):从 remark 提取或使用中文部分
- 繁体中文(tc_description):转换简体为繁体
- 越南语(vn_description):可选,如果用户提供则使用
- 法语(fr_description):可选
4. **生成 SQL 语句**
```sql
-- 插入 m_system_code
REPLACE INTO `g3fo_base`.`m_system_code`
(`id`, `code_type`, `code_value`, `description_i18n_id`, `remark`, `sort`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES
({new_id}, '{code_type}', '{code_value}', 'CODE-{formatted_id}', '{remark}', {sort}, 'sys', NOW(), 'sys', NOW());
-- 插入 m_system_i18n
REPLACE INTO `g3fo_base`.`m_system_i18n`
(`id`, `en_description`, `sc_description`, `tc_description`, `vn_description`, `fr_description`, `remark`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES
('CODE-{formatted_id}', '{en_description}', '{sc_description}', '{tc_description}', '{vn_description}', '{fr_description}', NULL, 'sys', NOW(), 'sys', NOW());
```
#### 步骤 3: 用户确认
向用户展示生成的 SQL 语句,询问:
```
已生成以下 SQL 语句,请确认数据是否正确:
[显示SQL语句]
数据是否有问题?(yes/no)
```
#### 步骤 4: 执行SQL
如果用户确认无误,使用 MySQL MCP 执行 SQL 语句:
1. 连接到数据库
2. 执行 SQL 语句
3. 验证执行结果
4. 如果成功,继续下一步;如果失败,报告错误并停止
#### 步骤 5: 询问是否提交到Git
执行成功后,询问用户:
```
SQL 执行成功!
是否需要将 SQL 提交到待执行文件夹中?(yes/no)
```
#### 步骤 6: Git 操作
如果用户确认提交,**必须按照以下顺序执行**,确保远程仓库和本地数据一致:
1. **切换到 g3fo-db 目录并拉取最新代码**(必须先执行,确保获取最新文件列表)
```bash
cd g3fo-db
git pull origin main # 或相应的分支名
```
- **重要**:这一步必须在确定文件夹和生成文件名之前执行
- 确保获取远程仓库的最新文件列表和更改
- 如果 pull 失败(如有冲突),报告错误并停止流程
2. **确定目标文件夹**(基于最新拉取的代码)
- 查找 `update_service_release` 下最新的 "pending release {version}" 文件夹
- **如果不存在,需要创建新的文件夹**:
- 查看 `update_service_release` 下所有版本号文件夹(如 `1.5.1.0`, `1.5.1.1`, `1.5.1.17` 等)
- 找到最大的版本号,新版本号 = 最大版本号 + 0.0.0.1(最后一位递增)
- 例如:如果最大版本号是 `1.5.1.17`,新版本号是 `1.5.1.18`
- 创建新文件夹:`pending release {新版本号}`
- **自动创建 `set_version_01.sql` 文件**(必须在新文件夹中创建):
- 文件内容格式:
```sql
UPDATE `g3fo_base`.`m_system_setting`
SET `param_value` = '1.5.1.0 M{版本号最后两位数字}',
`update_on` = NOW()
WHERE
`param_name` = 'base.systemVersion';
UPDATE `g3fo_base`.`m_system_setting`
SET `param_value` = '0',
`update_on` = NOW()
WHERE
`param_name` = 'base.patchNo';
```
- **版本号与 param_value 的对应关系**:
- 版本号 `1.5.1.17` → `param_value` = `'1.5.1.0 M17'`
- 版本号 `1.5.1.18` → `param_value` = `'1.5.1.0 M18'`
- 版本号 `1.5.1.19` → `param_value` = `'1.5.1.0 M19'`
- 版本号 `1.5.1.10` → `param_value` = `'1.5.1.0 M10'`
- **规律**:提取版本号的最后一部分数字(版本号格式为 X.Y.Z.N,提取 N),格式为 `'1.5.1.0 M{N}'`
- **示例**:
- `1.5.1.17` → 提取 `17` → `'1.5.1.0 M17'`
- `1.5.1.18` → 提取 `18` → `'1.5.1.0 M18'`
- `1.5.1.10` → 提取 `10` → `'1.5.1.0 M10'`
- `1.5.1.9` → 提取 `9` → `'1.5.1.0 M9'`(不补零,保持原数字)
- **注意**:此时文件夹列表是最新的,避免文件名冲突
3. **生成文件名**(基于最新的文件列表)
- 格式:`{功能描述英文}_{序号}.sql`
- 序号规则:
- **必须在 git pull 之后执行**,查看目标文件夹中已有的 SQL 文件(基于最新拉取的代码)
- **跨所有文件统一计算序号**,不区分文件名前缀
- **提取序号方法**:
1. 遍历文件夹中所有 `.sql` 文件
2. 从每个文件名中提取下划线 `_` 后面的两位数字(格式:`_XX.sql`)
3. 例如:`set_version_01.sql` → 提取 `01`,`add_system_code_02.sql` → 提取 `02`
4. 找到所有序号中的**最大值**
5. 新序号 = 最大序号 + 1
- 使用两位数字格式(01, 02, ..., 99)
- **示例**:
- 如果文件夹中有:`set_version_01.sql` 和 `add_system_code_02.sql`
- 提取的序号:`01`, `02`
- 最大序号:`02`
- 新文件序号:`03`
- 新文件名:`add_new_feature_03.sql`
- **重要**:确保序号不重复,必须基于最新拉取的代码生成
4. **检测并修复重复序号**(在保存文件之前)
- 扫描目标文件夹中所有 `.sql` 文件
- 检测是否有重复序号
- 如果发现重复,按照"5.4 重复序号检测和自动修复"规则处理
- 确保所有文件序号唯一且连续
- 如果进行了修复,生成修复报告并显示给用户
5. **保存 SQL 文件**
- 将 SQL 语句保存到目标文件夹
- 文件名使用生成的名称
6. **Git 提交和推送**
```bash
git add .
git commit -m "feat: add system code {code_type} - {code_value}"
git push origin main # 或相应的分支名
```
**如果 push 失败**(如远程有新的提交):
- 再次执行 `git pull origin main`(可能需要处理合并)
- 解决冲突后重新 push
#### 步骤 7: 完成提示
```
操作完成!
已执行的操作:
✓ SQL 语句已执行
✓ SQL 文件已保存到: update_service_release/pending release {version}/{filename}
✓ 已推送到 Git 仓库
```
## 四、其他表的处理规则
### 4.1 m_system_error_message
**输入数据:**
- Error_code: 错误码(数字)
- Message_i18n_id: 自动生成 `ERR-{error_code}`
- Remark: 英文描述
**i18n_id 生成:** `ERR-{error_code}`
**SQL 模板:**
```sql
REPLACE INTO `g3fo_base`.`m_system_error_message`
(`id`, `error_code`, `message_i18n_id`, `remark`)
VALUES
('{error_code}', 'SFO-{error_code}', 'ERR-{error_code}', '{remark}');
REPLACE INTO `g3fo_base`.`m_system_i18n`
(`id`, `en_description`, `sc_description`, `tc_description`, `vn_description`, `fr_description`, `remark`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES
('ERR-{error_code}', '{en_description}', '{sc_description}', '{tc_description}', '{vn_description}', '{fr_description}', NULL, 'sys', NOW(), 'sys', NOW());
```
### 4.2 m_market
**输入数据:**
- Market_code: 市场代码
- Market_name: 市场名称(用于生成i18n)
- 其他必要字段
**i18n_id 生成:** `MKT-{4位数字ID}`(需要先获取最大ID)
### 4.3 m_currency, m_channel, m_exchange, m_country
**输入数据:**
- Code: 代码(用于生成i18n_id)
- Name: 名称(用于生成i18n)
- 其他必要字段
**i18n_id 生成:**
- Currency: `CURR-{currency_code}`
- Channel: `CH-{channel_code}`
- Exchange: `EXCH-{exchange_code}`
- Country: `CNTY-{country_code}`
### 4.4 m_exchange_charge, m_company_charge
**输入数据:**
- 相关字段
- 描述信息(用于生成i18n)
**i18n_id 生成:**
- Exchange Charge: `EX_CHARGE-{id}`
- Company Charge: `COM_CHARGE-{id}`
## 五、文件命名规范
### 5.1 命名格式
```
{功能描述英文}_{序号}.sql
```
### 5.2 功能描述示例
- `add_system_code` - 添加系统代码
- `update_system_code` - 更新系统代码
- `add_system_error_message` - 添加错误消息
- `insert_system_route` - 插入系统路由
- `create_table_{table_name}` - 创建表
- `update_table_{table_name}_column` - 更新表列
- `add_{table_name}_data` - 添加表数据
### 5.3 序号规则
**重要:跨所有文件统一计算序号,不区分文件名前缀**
1. **查看目标文件夹中所有 `.sql` 文件**(基于最新拉取的代码)
2. **提取序号方法**:
- 遍历所有 `.sql` 文件
- 从每个文件名中提取下划线 `_` 后面的两位数字(格式:`_XX.sql`)
- 例如:
- `set_version_01.sql` → 提取 `01`
- `add_system_code_02.sql` → 提取 `02`
- `update_table_05.sql` → 提取 `05`
3. **找到所有序号中的最大值**
4. **新文件的序号 = 最大序号 + 1**
5. **使用两位数字格式(01-99)**
**示例:**
- 如果文件夹中有:`set_version_01.sql`, `add_system_code_02.sql`, `update_table_05.sql`
- 提取的序号:`01`, `02`, `05`
- 最大序号:`05`
- 新文件序号:`06`
- 新文件名:`add_new_feature_06.sql`(不限制文件名前缀)
**关键点:**
- 序号是跨所有文件统一计算的,不区分文件名前缀
- 即使已有 `xxxxxx_01.sql`,如果最大序号是 `01`,新文件应该是 `xxxxxx_02.sql`
- 如果文件夹中只有 `set_version_01.sql`,新文件应该是 `xxxxxx_02.sql`(不是 `01`)
### 5.4 重复序号检测和自动修复
**重要:在生成新文件或提交到 Git 之前,必须检测并修复重复序号**
#### 检测规则
1. **扫描目标文件夹**:检查 `update_service_release/pending release {version}/` 文件夹中所有 `.sql` 文件
2. **提取序号**:从每个文件名中提取下划线 `_` 后面的两位数字
3. **检测重复**:如果发现多个文件使用相同的序号,触发修复流程
#### 修复规则
当发现重复序号时(例如:`xxxxxx_03.sql` 和 `aaaaaaa_03.sql`),按以下步骤处理:
1. **分析文件依赖关系**:
- 比对两个文件的 SQL 内容
- 检查是否存在依赖关系:
- 文件 A 中引用了文件 B 创建的表、字段、数据等
- 文件 A 中使用了文件 B 中定义的存储过程、函数等
- 文件 A 中更新了文件 B 中插入的数据
- **依赖关系判断方法**:
- 检查 SQL 中的表名、字段名、数据值是否在另一个文件中出现
- 检查是否有 CREATE/DROP 操作在另一个文件中有对应的引用
- 检查是否有 INSERT/UPDATE 操作在另一个文件中有对应的查询
- 检查存储过程、函数的定义和调用关系
2. **确定文件顺序**:
- **如果有依赖关系**:
- 被依赖的文件(被引用)排在前面,保持原序号
- 依赖其他文件的排在后面,序号改为下一个可用序号
- **如果没有依赖关系**:
- 按照文件的创建时间(文件系统时间)确定先后顺序
- 创建时间较早的文件保持原序号
- 创建时间较晚的文件序号改为下一个可用序号
3. **自动顺延后续文件**:
- 找到下一个可用的序号(最大序号 + 1)
- 将重复序号中需要调整的文件重命名为新序号
- **检查后续文件是否需要顺延**:
- 如果新序号与后续文件序号冲突,自动顺延后续文件
- 例如:如果 `cccccc_04.sql` 和 `bbbbbbb_05.sql` 存在,且修复后新序号是 `04`
- 则 `cccccc_04.sql` → `cccccc_05.sql`,`bbbbbbb_05.sql` → `bbbbbbb_06.sql`
- 递归处理,直到没有冲突
4. **执行修复**:
- 使用 `git mv` 重命名文件(保持 Git 历史)
- 更新 Git 索引
- 生成修复报告,显示所有重命名的文件
#### 修复示例
**场景 1:有依赖关系**
- 文件:`create_table_03.sql`(创建表 `m_new_table`),`insert_data_03.sql`(向 `m_new_table` 插入数据)
- 检测:`insert_data_03.sql` 依赖 `create_table_03.sql`(引用了 `m_new_table`)
- 修复:
- `create_table_03.sql` 保持 `03`
- `insert_data_03.sql` → `insert_data_04.sql`
**场景 2:无依赖关系,按创建时间**
- 文件:`add_system_code_03.sql`(创建时间:2024-01-01),`update_setting_03.sql`(创建时间:2024-01-02)
- 检测:无依赖关系
- 修复:
- `add_system_code_03.sql` 保持 `03`(较早)
- `update_setting_03.sql` → `update_setting_04.sql`(较晚)
**场景 3:需要顺延后续文件**
- 文件:`file_a_03.sql`, `file_b_03.sql`, `file_c_04.sql`, `file_d_05.sql`
- 检测:`file_a_03.sql` 和 `file_b_03.sql` 重复,无依赖关系,`file_a_03.sql` 较早
- 修复:
- `file_a_03.sql` 保持 `03`
- `file_b_03.sql` → `file_b_04.sql`
- `file_c_04.sql` → `file_c_05.sql`(顺延,因为 `04` 已被占用)
- `file_d_05.sql` → `file_d_06.sql`(顺延,因为 `05` 已被占用)
**场景 4:多个重复序号**
- 文件:`file_a_03.sql`, `file_b_03.sql`, `file_c_04.sql`, `file_d_04.sql`, `file_e_05.sql`
- 检测:`03` 重复,`04` 也重复
- 修复:
- 先处理 `03` 的重复:`file_a_03.sql` 保持 `03`,`file_b_03.sql` → `file_b_04.sql`
- 再处理 `04` 的重复:`file_c_04.sql` 保持 `04`,`file_d_04.sql` → `file_d_05.sql`
- 顺延:`file_e_05.sql` → `file_e_06.sql`
#### 执行时机
- **在生成新文件之前**:先检测并修复现有文件的重复序号
- **在提交到 Git 之前**:再次检测并修复,确保没有重复序号
- **可以手动触发**:用户要求检测和修复时
#### 修复报告格式
修复完成后,生成报告:
```
检测到重复序号,已自动修复:
修复的文件:
- file_b_03.sql → file_b_04.sql(原因:与 file_a_03.sql 重复,无依赖关系,按创建时间调整)
- file_c_04.sql → file_c_05.sql(原因:序号冲突,自动顺延)
- file_d_05.sql → file_d_06.sql(原因:序号冲突,自动顺延)
所有文件序号已修复,无重复。
```
## 六、SQL 语句规范
### 6.1 使用 REPLACE INTO
对于数据插入和更新,使用 `REPLACE INTO` 而不是 `INSERT INTO`,以确保幂等性:
```sql
REPLACE INTO `schema`.`table_name`
(`column1`, `column2`, ...)
VALUES
('value1', 'value2', ...);
```
### 6.2 时间戳字段
- `create_on`: `NOW()` 或 `CURRENT_TIMESTAMP`
- `update_on`: `NOW()` 或 `CURRENT_TIMESTAMP`
- `create_by`: `'sys'`(系统操作)或实际用户名
- `update_by`: `'sys'`(系统操作)或实际用户名
### 6.3 注释
在 SQL 文件开头添加注释说明:
```sql
-- ===================================================================
-- 功能描述:添加系统代码
-- 表名:m_system_code, m_system_i18n
-- 创建时间:{date}
-- ===================================================================
```
## 七、Git 操作规范
### 7.1 操作顺序(重要)
**必须严格按照以下顺序执行 Git 操作,确保远程仓库和本地数据一致:**
1. **先执行 `git pull`** - 获取最新代码和文件列表
2. **然后确定目标文件夹** - 基于最新拉取的代码
3. **生成文件名** - 基于最新的文件列表,避免序号冲突
4. **保存文件** - 创建 SQL 文件
5. **最后执行 `git add`, `commit`, `push`** - 提交更改
**为什么必须先 pull?**
- 确保获取远程仓库的最新文件列表
- 避免文件名序号冲突(其他人可能已经添加了新文件)
- 避免覆盖其他人的更改
- 确保本地和远程仓库的一致性
### 7.2 Commit 消息格式
```
feat: {简短描述}
详细说明(可选)
```
**示例:**
- `feat: add system code OrderType - 015`
- `feat: add system error message SFO-17100`
- `feat: insert system route /trade/order/retryOrder`
### 7.3 分支管理
- 默认推送到 `main` 分支
- 如果项目使用其他分支策略,遵循项目规范
### 7.4 冲突处理
如果 `git pull` 时出现冲突:
1. 报告冲突文件
2. 询问用户是否手动解决
3. 或提供解决建议
4. **不要继续执行后续步骤**,直到冲突解决
如果 `git push` 时失败(远程有新的提交):
1. 再次执行 `git pull origin main`(可能需要处理合并)
2. 解决冲突后重新 push
## 八、错误处理
### 8.1 SQL 执行失败
- 显示错误信息
- 不执行 Git 操作
- 询问用户是否重试
### 8.2 Git 操作失败
- 显示错误信息
- SQL 文件已保存到本地
- 提供手动 Git 操作建议
### 8.3 数据验证失败
- 在生成 SQL 前验证数据格式
- 如果验证失败,提示用户修正
## 九、重要提醒
### 9.1 必须同时更新的表
1. **i18n 表更新**:所有需要多语言支持的表操作都必须同时更新 `m_system_i18n` 表
2. **订单表字段同步**:当 `m_order` 表增加字段时,必须同时在以下三个表中增加相同字段:
- `m_order_actions` - 订单操作表
- `h_order` - 订单历史表
- `h_order_actions` - 订单操作历史表
### 9.2 菜单和路径权限处理规则
**重要:增加菜单和路径权限必须使用存储过程文件**
1. **执行 SQL 阶段**:
- 由于 MySQL MCP 不支持 `DELIMITER`,可以使用直接的 `INSERT INTO` 或 `REPLACE INTO` 语句执行
- 确保数据与存储过程生成的数据完全一致
2. **提交到 Git 阶段**:
- **必须使用存储过程文件生成的完整 SQL**
- 从 `common_sql` 文件夹复制完整的存储过程定义
- 在文件末尾添加 `CALL` 语句
- 参考 `update_service_release/pending release 1.5.1.18` 中的文件格式
### 9.3 其他重要规则
1. 所有 SQL 文件必须保存到正确的版本文件夹中
2. **文件序号不能重复,必须递增。在生成新文件和提交到 Git 之前,必须检测并修复重复序号**
3. 使用 REPLACE INTO 确保 SQL 可以重复执行
4. 执行 SQL 前必须获得用户确认
5. 表结构变更必须使用存储过程进行幂等性检查
## 十、持续改进
本流程是一个持续更新和改进的流程。在使用过程中,如果发现以下情况,应该更新本文档:
1. 发现新的需要 i18n 的表
2. 发现新的需要同步字段的表(如订单表字段同步规则)
3. 发现新的命名规范或格式要求
4. 发现流程中的问题或改进点
5. 添加新的模板或工具
## 十一、使用示例
### 示例 1: 添加系统代码
**用户输入:**
```
我需要添加一个新的系统代码:
- Code_type: OrderType
- Code_value: 016
- Remark: Market Order (HK)
- Sort: 17
```
**Cursor 处理:**
1. 查询最大ID:假设当前最大ID是 404
2. 生成新ID:405
3. 生成 i18n_id:CODE-0405
4. 生成多语言描述:
- en: Market Order (HK)
- sc: 市价单(香港)
- tc: 市價單(香港)
- vn: (可选)
5. 生成 SQL 并展示
6. 用户确认后执行
7. 执行成功后询问是否提交到 Git
8. 如果确认,保存文件并推送到 Git
### 示例 2: 插入系统路由
**用户输入:**
```
我需要添加一个新的系统路由:
- Route: /trade/order/cancel
- Route_type: USER
- Remark: 取消订单
- Title_remark: 订单
```
**Cursor 处理:**
1. 使用 `insert_system_route_procedure.sql` 模板
2. 生成 SQL:
```sql
CALL InsertSystemRoute('取消订单', '/trade/order/cancel', '订单', 'USER');
```
3. 执行并提交到 Git
## 附录
### A. 常用 SQL 查询
**获取最大ID:**
```sql
SELECT COALESCE(MAX(id), 0) + 1 FROM g3fo_base.m_system_code;
```
**检查记录是否存在:**
```sql
SELECT COUNT(*) FROM g3fo_base.m_system_code
WHERE code_type = '{code_type}' AND code_value = '{code_value}';
```
**获取当前版本号:**
```sql
SELECT param_value FROM g3fo_base.m_system_setting
WHERE param_name = 'base.systemVersion';
```
### B. 多语言描述生成规则
1. **如果 remark 包含中英文:**
- 提取英文部分作为 `en_description`
- 提取中文部分作为 `sc_description`
- 转换简体为繁体作为 `tc_description`
2. **如果 remark 只有中文:**
- 使用 remark 作为 `sc_description` 和 `tc_description`
- 询问用户英文描述,或使用拼音/音译
3. **如果 remark 只有英文:**
- 使用 remark 作为 `en_description`
- 询问用户中文描述
### C. 联系和支持
如有问题或建议,请更新本文档或联系项目维护者。