# 数据库设计 **本文引用的文件** - [application.yaml](file://fms-api/src/main/resources/application.yaml) - [OrgContext.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgContext.java) - [OrgDataSourceFactory.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgDataSourceFactory.java) - [OrgDataSourceManager.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgDataSourceManager.java) - [OrgRoutingDataSource.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgRoutingDataSource.java) - [OrgDatabaseConfigLoader.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgDatabaseConfigLoader.java) - [100_initialize_fms_new.sql](file://fms-api/config/migrations/100_initialize_fms_new.sql) - [016_create_base_tables.sql](file://fms-api/config/migrations/016_create_base_tables.sql) - [018_create_business_tables.sql](file://fms-api/config/migrations/018_create_business_tables.sql) - [RunBusinessMigrations.java](file://fms-api/config/migrations/tools/RunBusinessMigrations.java) - [VerifyBusinessMigration.java](file://fms-api/config/migrations/tools/VerifyBusinessMigration.java) - [ApplySimpleModuleRestore.java](file://fms-api/config/migrations/tools/ApplySimpleModuleRestore.java) ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) 6. [依赖关系分析](#依赖关系分析) 7. [性能考虑](#性能考虑) 8. [故障排查指南](#故障排查指南) 9. [结论](#结论) 10. [附录](#附录) ## 简介 本文件面向FMS系统的数据库设计与运维,覆盖以下主题: - 核心表结构与实体关系:用户权限、模块定义、字段配置等元数据驱动的数据模型。 - 多租户数据隔离方案:基于orgId的上下文与连接路由机制。 - Flyway迁移管理策略:版本控制、回滚与一致性保障。 - 性能优化建议与索引设计原则。 - 备份恢复与运维管理指南。 ## 项目结构 FMS后端通过Spring Boot应用暴露API,数据库层采用按机构(orgId)动态创建与管理数据源的方式实现多租户隔离;业务与基础元数据通过SQL迁移脚本进行版本化管理。 ```mermaid graph TB A["应用配置
application.yaml"] --> B["运行时参数
连接池/路径"] B --> C["组织上下文
OrgContext"] C --> D["数据源管理器
OrgDataSourceManager"] D --> E["数据源工厂
OrgDataSourceFactory"] D --> F["配置加载器
OrgDatabaseConfigLoader"] E --> G["Druid连接池"] F --> H["机构配置文件
config/dbconfigs/*.properties"] D -.-> I["路由数据源
OrgRoutingDataSource"] I --> G ``` 图表来源 - [application.yaml:10-26](file://fms-api/src/main/resources/application.yaml#L10-L26) - [OrgContext.java:1-55](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgContext.java#L1-L55) - [OrgDataSourceManager.java:1-62](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgDataSourceManager.java#L1-L62) - [OrgDataSourceFactory.java:1-53](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgDataSourceFactory.java#L1-L53) - [OrgDatabaseConfigLoader.java:1-104](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgDatabaseConfigLoader.java#L1-L104) - [OrgRoutingDataSource.java:1-29](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgRoutingDataSource.java#L1-L29) 章节来源 - [application.yaml:1-34](file://fms-api/src/main/resources/application.yaml#L1-L34) ## 核心组件 - 多租户上下文与路由:通过ThreadLocal维护当前请求的orgId与userId,并由路由数据源根据上下文选择对应机构的数据源。 - 数据源生命周期管理:懒加载、缓存、关闭与清理,支持连接池健康检查与空闲连接保活。 - 机构配置加载:从文件系统读取机构专属数据库连接信息,并进行安全校验与默认值处理。 - 迁移工具链:提供运行、验证与回滚辅助工具,确保DDL/DML变更可追踪、可回退。 章节来源 - [OrgContext.java:1-55](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgContext.java#L1-L55) - [OrgRoutingDataSource.java:1-29](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgRoutingDataSource.java#L1-L29) - [OrgDataSourceManager.java:1-62](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgDataSourceManager.java#L1-L62) - [OrgDataSourceFactory.java:1-53](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgDataSourceFactory.java#L1-L53) - [OrgDatabaseConfigLoader.java:1-104](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgDatabaseConfigLoader.java#L1-L104) ## 架构总览 下图展示一次跨租户数据访问的关键调用链:从上下文获取orgId,到路由数据源选择具体数据源,再到Druid连接池获取连接执行SQL。 ```mermaid sequenceDiagram participant Client as "客户端" participant API as "服务接口" participant Ctx as "OrgContext" participant Router as "OrgRoutingDataSource" participant Manager as "OrgDataSourceManager" participant Factory as "OrgDataSourceFactory" participant Pool as "Druid连接池" Client->>API : "发起请求(携带orgId)" API->>Ctx : "设置/读取 orgId, userId" API->>Router : "getConnection()" Router->>Manager : "getConnection(orgId)" Manager->>Manager : "computeIfAbsent(orgId)" alt 首次访问 Manager->>Factory : "create(orgId, config)" Factory->>Pool : "初始化并返回连接" else 命中缓存 Manager->>Pool : "复用已有连接" end Pool-->>API : "返回数据库连接" API-->>Client : "返回结果" ``` 图表来源 - [OrgContext.java:1-55](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgContext.java#L1-L55) - [OrgRoutingDataSource.java:1-29](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgRoutingDataSource.java#L1-L29) - [OrgDataSourceManager.java:1-62](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgDataSourceManager.java#L1-L62) - [OrgDataSourceFactory.java:1-53](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgDataSourceFactory.java#L1-L53) ## 详细组件分析 ### 多租户数据隔离(orgId上下文与连接路由) - 上下文管理:使用ThreadLocal保存orgId与userId,提供set/get/require方法,并在请求结束时清理,避免线程污染。 - 路由策略:统一对外暴露Primary数据源,内部根据上下文动态选择目标机构的数据源。 - 配置加载:按orgId查找对应配置文件,强制要求SQL Server驱动,并对路径进行规范化与安全校验。 - 连接池:使用Druid,支持连接检测、空闲回收、保活ping,降低云环境NAT/防火墙导致的连接失效问题。 ```mermaid flowchart TD Start(["进入请求"]) --> SetCtx["设置 orgId/userId 上下文"] SetCtx --> GetDS["获取数据源(按orgId)"] GetDS --> Cache{"是否已缓存?"} Cache --> |是| Use["复用连接池"] Cache --> |否| LoadCfg["加载机构配置"] LoadCfg --> CreateDS["创建并初始化连接池"] CreateDS --> Use Use --> Exec["执行SQL"] Exec --> End(["结束并清理上下文"]) ``` 图表来源 - [OrgContext.java:1-55](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgContext.java#L1-L55) - [OrgDataSourceManager.java:1-62](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgDataSourceManager.java#L1-L62) - [OrgDatabaseConfigLoader.java:1-104](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgDatabaseConfigLoader.java#L1-L104) - [OrgDataSourceFactory.java:1-53](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgDataSourceFactory.java#L1-L53) 章节来源 - [OrgContext.java:1-55](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgContext.java#L1-L55) - [OrgRoutingDataSource.java:1-29](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgRoutingDataSource.java#L1-L29) - [OrgDataSourceManager.java:1-62](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgDataSourceManager.java#L1-L62) - [OrgDatabaseConfigLoader.java:1-104](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgDatabaseConfigLoader.java#L1-L104) - [OrgDataSourceFactory.java:1-53](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgDataSourceFactory.java#L1-L53) ### 元数据驱动的数据模型(模块、字段、视图、编辑、查询、关系) 系统通过一组元数据表描述“模块-字段-视图-编辑-查询-关系”的配置,从而动态生成表单、列表、查询条件与关联关系,减少硬编码。 ```mermaid erDiagram S_MODULE ||--o{ S_FIELD : "包含" S_MODULE ||--o{ S_FIELD_VIEW : "显示配置" S_MODULE ||--o{ S_FIELD_EDIT : "编辑配置" S_MODULE ||--o{ S_FIELD_QUERY : "查询配置" S_MODULE ||--o{ S_RELATION : "定义关系" S_FIELD ||--o{ S_FIELD_VIEW : "被引用" S_FIELD ||--o{ S_FIELD_EDIT : "被引用" S_FIELD ||--o{ S_FIELD_QUERY : "被引用" S_MODULE ||--o{ S_MENU : "菜单映射" S_MODULE ||--o{ S_AUTOCODE : "自动编号" ``` 图表来源 - [100_initialize_fms_new.sql:56-243](file://fms-api/config/migrations/100_initialize_fms_new.sql#L56-L243) 说明要点 - 模块表:定义业务模块类型(分类/数据/查询)、视图表、保存表、主键字段、排序字段、删除策略等。 - 字段表:定义字段名、显示名、数据类型、长度、精度、可空、默认值、写入模式(直写/只读/计算/系统)等。 - 视图/编辑/查询配置:分别控制列表显示、表单编辑、查询条件的可见性、顺序、占位符、列宽等。 - 关系表:支持一对一、一对多、多对一、多对多,含级联删除策略、排序字段等。 - 菜单与自动编号:菜单树与模块绑定;自动编号规则支持前缀、日期格式、分隔符、周期重置等。 章节来源 - [100_initialize_fms_new.sql:56-243](file://fms-api/config/migrations/100_initialize_fms_new.sql#L56-L243) ### 权限体系(角色、权限、范围) 权限模型围绕“角色-权限-范围”展开,支持菜单、模块、动作、字段四类资源,以及多种数据范围策略(全部、创建者、拥有者、部门、部门树、自定义)。 ```mermaid classDiagram class 角色 { +b_id +b_code +b_name +b_is_system +b_bypass_power } class 权限 { +b_id +b_code +b_name +b_power_type +b_resource +b_module_id +b_field_id +b_operation } class 角色_权限 { +b_role_id +b_power_id +b_effect } class 角色_范围 { +b_role_id +b_module_id +b_operation +b_scope_type +b_scope_field_id +b_scope_value } 角色 "1" -- "many" 角色_权限 : "授权" 权限 "1" -- "many" 角色_权限 : "被授权" 角色 "1" -- "many" 角色_范围 : "数据范围" ``` 图表来源 - [100_initialize_fms_new.sql:291-394](file://fms-api/config/migrations/100_initialize_fms_new.sql#L291-L394) 章节来源 - [100_initialize_fms_new.sql:291-394](file://fms-api/config/migrations/100_initialize_fms_new.sql#L291-L394) ### 日志与审计(技术日志、登录日志、审计日志) 系统提供三类日志表,用于技术排障、登录审计与业务操作审计,均带时间戳与追踪ID,便于链路追踪与聚合分析。 ```mermaid erDiagram S_LOG_TECHNICAL { bigint b_id PK varchar b_account varchar b_loglevel varchar b_trace_id bigint b_duration_ms datetime2 b_occurdatetime } S_LOG_LOGIN { bigint b_id PK varchar b_account int b_login_result varchar b_trace_id datetime2 b_occurdatetime } S_LOG_AUDIT { bigint b_id PK varchar b_event_code varchar b_module_code varchar b_data_id varchar b_trace_id datetime2 b_occurdatetime } S_LOG_AUDIT_FIELD { bigint b_id PK bigint b_event_id FK varchar b_field text b_before_value text b_after_value } S_LOG_AUDIT ||--o{ S_LOG_AUDIT_FIELD : "包含" ``` 图表来源 - [100_initialize_fms_new.sql:411-507](file://fms-api/config/migrations/100_initialize_fms_new.sql#L411-L507) 章节来源 - [100_initialize_fms_new.sql:411-507](file://fms-api/config/migrations/100_initialize_fms_new.sql#L411-L507) ### 基础资料与业务单据(示例) - 基础资料:如币种、汇率、港口、船公司、状态字典等,作为全局或租户内共享参考数据。 - 业务单据:以业务单为主表,子表包括集装箱、财务明细等,体现典型的主从结构。 ```mermaid erDiagram BS_BUSINESS { bigint b_id PK varchar b_ywno UK datetime2 b_orderdate bigint b_customer_id bigint b_mycompany_id } BS_BUSINESS_CONTAINER { bigint subid PK bigint father FK varchar mx_con_no decimal mx_con_gw } BS_BUSINESS_CW { bigint subid PK bigint father FK decimal mx_amount } BS_BUSINESS ||--o{ BS_BUSINESS_CONTAINER : "包含" BS_BUSINESS ||--o{ BS_BUSINESS_CW : "包含" ``` 图表来源 - [018_create_business_tables.sql:10-177](file://fms-api/config/migrations/018_create_business_tables.sql#L10-L177) 章节来源 - [016_create_base_tables.sql:1-747](file://fms-api/config/migrations/016_create_base_tables.sql#L1-L747) - [018_create_business_tables.sql:1-200](file://fms-api/config/migrations/018_create_business_tables.sql#L1-L200) ## 依赖关系分析 - 组件耦合:OrgRoutingDataSource仅依赖OrgDataSourceManager;Manager依赖ConfigLoader与Factory;Factory依赖Druid与全局连接池配置。 - 外部依赖:SQL Server JDBC驱动、Druid连接池、文件系统(机构配置)。 - 潜在风险:若未正确设置orgId上下文,将抛出异常;若配置文件路径不合法或内容缺失,将拒绝启动或连接。 ```mermaid graph LR Router["OrgRoutingDataSource"] --> Manager["OrgDataSourceManager"] Manager --> Loader["OrgDatabaseConfigLoader"] Manager --> Factory["OrgDataSourceFactory"] Factory --> Druid["Druid连接池"] Loader --> FS["文件系统(机构配置)"] ``` 图表来源 - [OrgRoutingDataSource.java:1-29](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgRoutingDataSource.java#L1-L29) - [OrgDataSourceManager.java:1-62](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgDataSourceManager.java#L1-L62) - [OrgDatabaseConfigLoader.java:1-104](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgDatabaseConfigLoader.java#L1-L104) - [OrgDataSourceFactory.java:1-53](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgDataSourceFactory.java#L1-L53) 章节来源 - [application.yaml:10-26](file://fms-api/src/main/resources/application.yaml#L10-L26) ## 性能考虑 - 连接池调优 - 初始大小与最小空闲设为0,按需创建,降低冷启动开销。 - 最大活跃连接数限制并发,防止资源耗尽。 - 启用空闲检测与保活ping,对抗云环境TCP会话回收。 - 索引设计原则 - 主键与唯一约束:所有核心表使用bigint主键与必要唯一约束(如模块代码、账号)。 - 高频查询列建复合索引:例如模块树(parent_id, xh, canuse)、字段与视图排序(xh, id)。 - 外键与关联查询:为常见关联列建立索引(如业务单的客户、公司、销售等)。 - 日志表:按时间倒序与追踪ID建索引,提升回溯效率。 - 查询优化建议 - 优先使用视图与物化视图(如有)简化复杂查询。 - 避免在WHERE中对字段进行函数转换,保持索引有效。 - 分页查询结合排序字段,减少全表扫描。 - 事务与批处理 - 批量导入/导出使用批处理提交,减少往返次数。 - 大事务拆分为小事务,降低锁竞争与回滚成本。 章节来源 - [application.yaml:10-26](file://fms-api/src/main/resources/application.yaml#L10-L26) - [100_initialize_fms_new.sql:56-243](file://fms-api/config/migrations/100_initialize_fms_new.sql#L56-L243) - [018_create_business_tables.sql:10-177](file://fms-api/config/migrations/018_create_business_tables.sql#L10-L177) ## 故障排查指南 - 常见问题定位 - 未设置orgId上下文:会抛出“当前请求未设置机构上下文”,需在请求入口设置。 - 机构码非法或配置文件缺失:加载器会抛出“机构码格式不正确”或“机构码错误”。 - 非SQL Server驱动:加载器强制要求SQL Server驱动,否则拒绝连接。 - 连接池异常:Druid初始化失败时抛出“初始化机构数据库连接池失败”,需检查网络与凭据。 - 迁移与一致性 - 迁移工具会在目标库名称校验后执行,防止误操作其他库。 - 支持分批执行与事务回滚,确保DDL/DML变更原子性。 - 提供验证工具,比对预期表结构与视图数量,确保迁移完整性。 - 回滚策略 - 针对特定修复脚本,可通过工具类执行并支持--verify-only模式进行预检。 - 建议在变更前备份关键表结构,必要时回滚至上一稳定版本。 章节来源 - [OrgContext.java:1-55](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgContext.java#L1-L55) - [OrgDatabaseConfigLoader.java:1-104](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgDatabaseConfigLoader.java#L1-L104) - [OrgDataSourceFactory.java:1-53](file://fms-api/src/main/java/cn/g3soft/fmsapi/database/OrgDataSourceFactory.java#L1-L53) - [RunBusinessMigrations.java:34-58](file://fms-api/config/migrations/tools/RunBusinessMigrations.java#L34-L58) - [VerifyBusinessMigration.java:37-68](file://fms-api/config/migrations/tools/VerifyBusinessMigration.java#L37-L68) - [ApplySimpleModuleRestore.java:1-58](file://fms-api/config/migrations/tools/ApplySimpleModuleRestore.java#L1-L58) ## 结论 FMS数据库设计以元数据驱动为核心,通过模块、字段、视图、编辑、查询与关系等配置表,灵活构建业务界面与逻辑;借助orgId上下文与动态数据源路由实现多租户隔离;通过Flyway风格的迁移脚本与配套工具保证版本可控与一致性;配合合理的索引与连接池调优,满足高并发与可扩展需求。建议在生产环境中严格执行迁移流程与备份策略,持续监控性能指标并及时优化。 ## 附录 - 备份与恢复建议 - 定期全量备份与增量日志备份,保留足够历史窗口。 - 迁移前对关键表结构进行快照备份,便于快速回滚。 - 恢复后进行一致性校验(表数量、视图数量、索引统计)。 - 运维管理清单 - 监控连接池使用率、等待时间与错误率。 - 定期检查机构配置文件的有效性与权限。 - 审计日志归档与清理策略,避免磁盘占用过高。 - 迁移脚本纳入CI/CD流水线,自动化执行与报告。