18 KiB
18 KiB
数据库设计
**本文引用的文件** - [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)目录
简介
本文件面向FMS系统的数据库设计与运维,覆盖以下主题:
- 核心表结构与实体关系:用户权限、模块定义、字段配置等元数据驱动的数据模型。
- 多租户数据隔离方案:基于orgId的上下文与连接路由机制。
- Flyway迁移管理策略:版本控制、回滚与一致性保障。
- 性能优化建议与索引设计原则。
- 备份恢复与运维管理指南。
项目结构
FMS后端通过Spring Boot应用暴露API,数据库层采用按机构(orgId)动态创建与管理数据源的方式实现多租户隔离;业务与基础元数据通过SQL迁移脚本进行版本化管理。
graph TB
A["应用配置<br/>application.yaml"] --> B["运行时参数<br/>连接池/路径"]
B --> C["组织上下文<br/>OrgContext"]
C --> D["数据源管理器<br/>OrgDataSourceManager"]
D --> E["数据源工厂<br/>OrgDataSourceFactory"]
D --> F["配置加载器<br/>OrgDatabaseConfigLoader"]
E --> G["Druid连接池"]
F --> H["机构配置文件<br/>config/dbconfigs/*.properties"]
D -.-> I["路由数据源<br/>OrgRoutingDataSource"]
I --> G
图表来源
- application.yaml:10-26
- OrgContext.java:1-55
- OrgDataSourceManager.java:1-62
- OrgDataSourceFactory.java:1-53
- OrgDatabaseConfigLoader.java:1-104
- OrgRoutingDataSource.java:1-29
章节来源
核心组件
- 多租户上下文与路由:通过ThreadLocal维护当前请求的orgId与userId,并由路由数据源根据上下文选择对应机构的数据源。
- 数据源生命周期管理:懒加载、缓存、关闭与清理,支持连接池健康检查与空闲连接保活。
- 机构配置加载:从文件系统读取机构专属数据库连接信息,并进行安全校验与默认值处理。
- 迁移工具链:提供运行、验证与回滚辅助工具,确保DDL/DML变更可追踪、可回退。
章节来源
- OrgContext.java:1-55
- OrgRoutingDataSource.java:1-29
- OrgDataSourceManager.java:1-62
- OrgDataSourceFactory.java:1-53
- OrgDatabaseConfigLoader.java:1-104
架构总览
下图展示一次跨租户数据访问的关键调用链:从上下文获取orgId,到路由数据源选择具体数据源,再到Druid连接池获取连接执行SQL。
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
- OrgRoutingDataSource.java:1-29
- OrgDataSourceManager.java:1-62
- OrgDataSourceFactory.java:1-53
详细组件分析
多租户数据隔离(orgId上下文与连接路由)
- 上下文管理:使用ThreadLocal保存orgId与userId,提供set/get/require方法,并在请求结束时清理,避免线程污染。
- 路由策略:统一对外暴露Primary数据源,内部根据上下文动态选择目标机构的数据源。
- 配置加载:按orgId查找对应配置文件,强制要求SQL Server驱动,并对路径进行规范化与安全校验。
- 连接池:使用Druid,支持连接检测、空闲回收、保活ping,降低云环境NAT/防火墙导致的连接失效问题。
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
- OrgDataSourceManager.java:1-62
- OrgDatabaseConfigLoader.java:1-104
- OrgDataSourceFactory.java:1-53
章节来源
- OrgContext.java:1-55
- OrgRoutingDataSource.java:1-29
- OrgDataSourceManager.java:1-62
- OrgDatabaseConfigLoader.java:1-104
- OrgDataSourceFactory.java:1-53
元数据驱动的数据模型(模块、字段、视图、编辑、查询、关系)
系统通过一组元数据表描述“模块-字段-视图-编辑-查询-关系”的配置,从而动态生成表单、列表、查询条件与关联关系,减少硬编码。
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 : "自动编号"
图表来源
说明要点
- 模块表:定义业务模块类型(分类/数据/查询)、视图表、保存表、主键字段、排序字段、删除策略等。
- 字段表:定义字段名、显示名、数据类型、长度、精度、可空、默认值、写入模式(直写/只读/计算/系统)等。
- 视图/编辑/查询配置:分别控制列表显示、表单编辑、查询条件的可见性、顺序、占位符、列宽等。
- 关系表:支持一对一、一对多、多对一、多对多,含级联删除策略、排序字段等。
- 菜单与自动编号:菜单树与模块绑定;自动编号规则支持前缀、日期格式、分隔符、周期重置等。
章节来源
权限体系(角色、权限、范围)
权限模型围绕“角色-权限-范围”展开,支持菜单、模块、动作、字段四类资源,以及多种数据范围策略(全部、创建者、拥有者、部门、部门树、自定义)。
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" 角色_范围 : "数据范围"
图表来源
章节来源
日志与审计(技术日志、登录日志、审计日志)
系统提供三类日志表,用于技术排障、登录审计与业务操作审计,均带时间戳与追踪ID,便于链路追踪与聚合分析。
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 : "包含"
图表来源
章节来源
基础资料与业务单据(示例)
- 基础资料:如币种、汇率、港口、船公司、状态字典等,作为全局或租户内共享参考数据。
- 业务单据:以业务单为主表,子表包括集装箱、财务明细等,体现典型的主从结构。
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 : "包含"
图表来源
章节来源
依赖关系分析
- 组件耦合:OrgRoutingDataSource仅依赖OrgDataSourceManager;Manager依赖ConfigLoader与Factory;Factory依赖Druid与全局连接池配置。
- 外部依赖:SQL Server JDBC驱动、Druid连接池、文件系统(机构配置)。
- 潜在风险:若未正确设置orgId上下文,将抛出异常;若配置文件路径不合法或内容缺失,将拒绝启动或连接。
graph LR
Router["OrgRoutingDataSource"] --> Manager["OrgDataSourceManager"]
Manager --> Loader["OrgDatabaseConfigLoader"]
Manager --> Factory["OrgDataSourceFactory"]
Factory --> Druid["Druid连接池"]
Loader --> FS["文件系统(机构配置)"]
图表来源
- OrgRoutingDataSource.java:1-29
- OrgDataSourceManager.java:1-62
- OrgDatabaseConfigLoader.java:1-104
- OrgDataSourceFactory.java:1-53
章节来源
性能考虑
- 连接池调优
- 初始大小与最小空闲设为0,按需创建,降低冷启动开销。
- 最大活跃连接数限制并发,防止资源耗尽。
- 启用空闲检测与保活ping,对抗云环境TCP会话回收。
- 索引设计原则
- 主键与唯一约束:所有核心表使用bigint主键与必要唯一约束(如模块代码、账号)。
- 高频查询列建复合索引:例如模块树(parent_id, xh, canuse)、字段与视图排序(xh, id)。
- 外键与关联查询:为常见关联列建立索引(如业务单的客户、公司、销售等)。
- 日志表:按时间倒序与追踪ID建索引,提升回溯效率。
- 查询优化建议
- 优先使用视图与物化视图(如有)简化复杂查询。
- 避免在WHERE中对字段进行函数转换,保持索引有效。
- 分页查询结合排序字段,减少全表扫描。
- 事务与批处理
- 批量导入/导出使用批处理提交,减少往返次数。
- 大事务拆分为小事务,降低锁竞争与回滚成本。
章节来源
故障排查指南
- 常见问题定位
- 未设置orgId上下文:会抛出“当前请求未设置机构上下文”,需在请求入口设置。
- 机构码非法或配置文件缺失:加载器会抛出“机构码格式不正确”或“机构码错误”。
- 非SQL Server驱动:加载器强制要求SQL Server驱动,否则拒绝连接。
- 连接池异常:Druid初始化失败时抛出“初始化机构数据库连接池失败”,需检查网络与凭据。
- 迁移与一致性
- 迁移工具会在目标库名称校验后执行,防止误操作其他库。
- 支持分批执行与事务回滚,确保DDL/DML变更原子性。
- 提供验证工具,比对预期表结构与视图数量,确保迁移完整性。
- 回滚策略
- 针对特定修复脚本,可通过工具类执行并支持--verify-only模式进行预检。
- 建议在变更前备份关键表结构,必要时回滚至上一稳定版本。
章节来源
- OrgContext.java:1-55
- OrgDatabaseConfigLoader.java:1-104
- OrgDataSourceFactory.java:1-53
- RunBusinessMigrations.java:34-58
- VerifyBusinessMigration.java:37-68
- ApplySimpleModuleRestore.java:1-58
结论
FMS数据库设计以元数据驱动为核心,通过模块、字段、视图、编辑、查询与关系等配置表,灵活构建业务界面与逻辑;借助orgId上下文与动态数据源路由实现多租户隔离;通过Flyway风格的迁移脚本与配套工具保证版本可控与一致性;配合合理的索引与连接池调优,满足高并发与可扩展需求。建议在生产环境中严格执行迁移流程与备份策略,持续监控性能指标并及时优化。
附录
- 备份与恢复建议
- 定期全量备份与增量日志备份,保留足够历史窗口。
- 迁移前对关键表结构进行快照备份,便于快速回滚。
- 恢复后进行一致性校验(表数量、视图数量、索引统计)。
- 运维管理清单
- 监控连接池使用率、等待时间与错误率。
- 定期检查机构配置文件的有效性与权限。
- 审计日志归档与清理策略,避免磁盘占用过高。
- 迁移脚本纳入CI/CD流水线,自动化执行与报告。