# 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 阶段 使用 **db_ops.py**(Python 数据库工具,替代 MCP MySQL)执行 SQL: 1. **批量执行含 DELIMITER 的存储过程文件**: - 使用 `python scripts/db_ops.py batch_execute --file path/to/file.sql` - db_ops.py 支持 DELIMITER,可正确解析并执行存储过程 2. **或使用 call_procedure 调用已存在的存储过程**: - `python scripts/db_ops.py call_procedure InsertSystemMenu --params "..." "..." "..."` 3. **或使用直接的 INSERT/REPLACE 语句**: - 使用 `execute` 命令执行 `INSERT INTO` 或 `REPLACE INTO` - 确保数据与存储过程生成的数据完全一致 4. **数据一致性要求**: - 菜单数据必须插入到 `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 如果用户确认无误,使用 **db_ops.py** 执行 SQL 语句: 1. 在终端执行:`python .claude/skills/g3fo-db-ops/scripts/db_ops.py execute "SQL"` 或 `batch_execute --file path` 2. 默认连接:host 192.168.3.233, user root, password afe123456;可通过 `--database g3fo_base` 或 `g3fo_trade` 指定库 3. 用户可提供不同连接信息时,使用 `--host`, `--port`, `--user`, `--password`, `--database` 覆盖 4. 验证执行结果(JSON 输出中 `"success": true`) 5. 如果成功,继续下一步;如果失败,报告错误并停止 #### 步骤 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 阶段**: - 使用 **db_ops.py** 的 `batch_execute --file` 执行含 DELIMITER 的存储过程文件 - 或使用 `call_procedure` 调用已存在的存储过程 - 或使用 `execute` 配合直接的 `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. 联系和支持 如有问题或建议,请更新本文档或联系项目维护者。