Files
workspace/code/fms/.codebuddy/plans/field-name-sync-from-old-db_f94a2b08.md
T
2026-07-30 17:30:13 +08:00

117 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: field-name-sync-from-old-db
overview: 创建可复用的字段名同步服务,从旧库 s_columnLib.col_Caption 同步到新库 s_module_field.b_name,按视图名和字段名匹配,首批执行 v_b_othercompany。
todos:
- id: fix-old-db-ssl
content: 修复 g3hd-old.properties:移除 sslProtocol=TLSv1 参数,JDK 21 驱动自动协商 TLSv1.2 即可连通
status: completed
- id: create-sync-service
content: 新建 FieldNameSyncService.java:实现跨库 UPDATE SQL,按 viewName 匹配 s_columnLib,将 col_Caption 写入 s_module_field.b_name,不匹配字段不改动,返回更新行数
status: completed
dependencies:
- fix-old-db-ssl
- id: create-admin-controller
content: 新建 AdminController.java,添加 POST /api/admin/sync-field-names 端点,JWT 认证,viewName 参数白名单校验,调用 FieldNameSyncService 并返回 ApiResponse
status: completed
dependencies:
- create-sync-service
- id: add-sql-migration-ref
content: 新建 023_sync_field_names.sql 参考脚本,记录跨库同步 SQL 作为纯 SQL 手动执行备选方案
status: completed
---
## 用户需求
构建一个可复用的工具,将旧库 `G3HY2025.dbo.s_columnLib` 中存储的字段中文名称(`col_Caption`)同步到新库 `fms.dbo.s_module_field.b_name`。
### 匹配规则
- `s_module.b_viewtable` = `s_columnLib.col_TableName`(模块视图名对应旧库表名)
- `s_module_field.b_field` = `s_columnLib.col_FieldName`(字段名精确匹配)
- 匹配不上的字段,`b_name` 保持不变
### 首批同步目标
视图 `v_b_othercompany`
### 可复用要求
以后还有更多视图需要同步,工具须参数化视图名,方便批量复用。
## 技术方案
### 方案选择:跨库 SQL + 管理端点
**核心决策**:新旧库在同一 SQL Server 实例(`118.89.70.199:1433`),使用**跨数据库 SQL** 直接从新库连接执行 `UPDATE ... FROM G3HY2025.dbo.s_columnLib`,无需单独连接旧库。
```sql
UPDATE sf
SET sf.b_name = LTRIM(RTRIM(sc.col_Caption))
FROM dbo.s_module_field sf
JOIN dbo.s_module m ON m.b_id = sf.b_module_id
JOIN G3HY2025.dbo.s_columnLib sc
ON sc.col_TableName = m.b_viewtable
AND sc.col_FieldName = sf.b_field
WHERE m.b_viewtable = ?
AND sc.col_Caption IS NOT NULL
AND LTRIM(RTRIM(sc.col_Caption)) != '';
```
**为何需要新端点而非复用通用端点**:
- 通用 `saveObjectApi` 只能操作当前 org 数据库的单表 insert/update/delete,无法表达跨库 JOIN 逻辑
- 通用 `loadDataApi` 只能查询当前 org 的表,无法读取旧库 `s_columnLib`
- 此操作为管理类批量数据同步,不在业务 CRUD 范畴内
### 实现架构
```mermaid
flowchart LR
A[前端/管理员] -->|POST /api/admin/sync-field-names| B[AdminController]
B -->|校验 viewName 参数| C[FieldNameSyncService]
C -->|获取新库 Connection| D[OrgRoutingDataSource]
D -->|fms 连接| E[(SQL Server)]
E -->|跨库 JOIN| F[G3HY2025.dbo.s_columnLib]
E -->|UPDATE| G[fms.dbo.s_module_field]
C -->|返回同步数量| B
B -->|ApiResponse| A
```
### 模块划分
| 模块 | 文件 | 职责 |
| --- | --- | --- |
| 配置修复 | `config/dbconfigs/g3hd-old.properties` | 移除 `sslProtocol=TLSv1` |
| 同步服务 | `service/FieldNameSyncService.java` | 执行跨库 UPDATE,校验参数,返回影响行数 |
| 管理控制器 | `controller/AdminController.java` | `POST /api/admin/sync-field-names` 端点,JWT 保护 |
| 参考脚本 | `config/migrations/023_sync_field_names.sql` | 纯 SQL 版本供手动执行 |
### 数据流
1. 前端/管理员发送 `POST /api/admin/sync-field-names`,请求体 `{ "viewName": "v_b_othercompany" }`
2. `AdminController` 校验 `viewName` 为合法标识符(字母/下划线/数字,最长128)
3. `FieldNameSyncService` 通过 `@Resource DataSource` 获取新库连接
4. 执行跨库 PreparedStatement UPDATE
5. 返回 `{ "updatedCount": 42, "message": "v_b_othercompany 同步完成,共更新 42 个字段名称" }`
### 安全措施
- `viewName` 参数:白名单正则 `^[A-Za-z_][A-Za-z0-9_]{0,127},校验后作为 PreparedStatement 参数绑定(非字符串拼接)
- JWT 认证:`AdminController` 路径 `/api/admin/**` 经 `JwtAuthFilter` 保护,仅登录用户可调用
- 失败不影响现有数据:UPDATE 在一条 SQL 内执行,单条匹配失败不阻断其他行
### 执行说明
- **热路径**:单条 UPDATE SQL 跨库 JOIN,性能取决于 `s_module_field` 行数和索引;对单个视图(~50 字段)毫秒级完成
- **日志**:服务层记录同步开始/完成/失败日志,使用 `@Slf4j`,级别 INFO/ERROR
- **事务**:使用 Spring 声明式事务 `@Transactional`,确保整批同步原子提交或回滚
- **向后兼容**:不修改现有 `DataController` 和通用端点,不影响业务数据流
## Agent Extensions
### SubAgent
- **code-explorer**
- 目的:探索旧库连接方式、现有 Service/Controller 模式、参数校验惯例
- 预期结果:确认 `OrgDataSourceManager` 的 API 使用方式和现有异常处理/日志模式