JavaProjectRepo/framework/docs/数据库初始方案.md

134 lines
6.4 KiB
Markdown
Raw Normal View History

# 数据库初始方案framework
## 目标
-`framework` 目录下建立 `db-init` 初始化目录,保存基础结构与基础数据。
- 支持从 MySQL 导出一份“初始化用”的基线数据,并在应用启动时自动检测是否已初始化;若未初始化,自动导入。
- 过程可重复、可审计、可在 `dev``server` 环境下安全运行。
## 目录结构规划
- `framework/db-init/`
- `sql/`
- `base-schema.sql`:基础库结构(表、索引、约束);可由 `mysqldump --no-data` 导出。
- `base-data.sql`:初始化数据(字典、默认角色、管理员等);可由 `mysqldump --no-create-info` 导出或手写。
- `scripts/`
- `export.ps1`Windows 导出脚本PowerShell
- `import.ps1`Windows 导入脚本PowerShell
- `export.sh`Linux/Mac 导出脚本(可选)。
- `import.sh`Linux/Mac 导入脚本(可选)。
- `README.md`:说明如何导出/导入、注意事项与环境变量。
## MySQL 导出策略
- 推荐使用 `mysqldump` 分离结构与数据,以便初始化时灵活控制:
- 结构:`mysqldump -h$DB_HOST -P$DB_PORT -u$DB_USER -p$DB_PASSWORD --no-data --databases $DB_NAME > sql/base-schema.sql`
- 数据:`mysqldump -h$DB_HOST -P$DB_PORT -u$DB_USER -p$DB_PASSWORD --no-create-info --databases $DB_NAME --tables <白名单表> > sql/base-data.sql`
- 数据白名单建议包含:
- 字典/配置表(如 `sys_dict`, `sys_config`
- 权限/角色/菜单(如 `sys_user`(仅管理员)、`sys_role`, `sys_menu`, `sys_user_role`, `sys_role_menu`
- 地区或静态映射表(如有)
- 机密信息与动态数据不导出:
- 排除审计日志、任务运行记录、业务动态表等。
## 导入策略
- 应用启动时进行“初始化检测”:
- 建议引入标记表:`app_init`(单行),字段 `initialized boolean`, `version varchar`,或在 `sys_config` 中维护 `init_done` 键。
- 检测逻辑:
- 若标记不存在或值为 `false`,视为未初始化。
- 若存在且为 `true`,跳过初始化。
- 导入步骤(未初始化时):
- 执行 `base-schema.sql`(若目标库为空或需校正结构时)。
- 执行 `base-data.sql`(插入/更新缺失的基线数据,注意幂等性)。
- 更新标记为已初始化,并记录版本与时间戳。
- 幂等性建议:
- 数据插入使用“存在则跳过/更新”策略(`INSERT ... ON DUPLICATE KEY UPDATE` 或先查询再写入)。
- 避免覆盖已有业务数据;仅在缺失时补充。
## Spring Boot 集成方案
- 方案 A轻量在后端增加初始化 Runner
- 新增一个 `@Component` 实现 `ApplicationRunner``CommandLineRunner``DataInitializer`
- 启动时:检查标记 → 未初始化则依次执行 `sql/base-schema.sql``sql/base-data.sql`
- SQL 执行方式:
- 直接通过 JDBC 读取并执行 SQL 文件(分号切分、事务包裹、失败回滚)。
- 或调用外部 `mysql` 命令(需服务器已安装 `mysql` 客户端,适合运维环境)。
- Profile 控制:默认仅在 `server``dev` 首次运行时启用;可通过配置 `app.init.enabled=true/false` 控制。
- 方案 B推荐中长期引入数据库版本管理工具
- `Flyway``Liquibase` 管理结构与数据变更;将初始化作为 `V1__base.sql` 脚本。
- 优点:变更有版本与校验,部署一致性更强;缺点:需要改造现有 SQL 并纳入流水线。
## 配置示例
- `application-server.yml` 中添加:
```
app:
init:
enabled: true
schema: classpath:db-init/sql/base-schema.sql
data: classpath:db-init/sql/base-data.sql
marker-table: app_init
marker-version: v1.0.0
```
- 路径策略:
- 若以资源方式打包,建议将 `db-init/sql` 复制到 `src/main/resources/db-init/sql`
- 或保留在项目根并通过绝对/相对路径访问(需考虑部署路径与权限)。
## 脚本示例Windows PowerShell
- `framework/db-init/scripts/export.ps1`
```
param(
[string]$DB_HOST = "43.138.168.68",
[int]$DB_PORT = 3306,
[string]$DB_NAME = "frameworkdb2025",
[string]$DB_USER = "root",
[string]$DB_PASSWORD = "ylfw20230626@"
)
$env:MYSQL_PWD = $DB_PASSWORD
# 导出结构
mysqldump -h $DB_HOST -P $DB_PORT -u $DB_USER --no-data --databases $DB_NAME > ../sql/base-schema.sql
# 按需导出数据(示例表名可调整)
mysqldump -h $DB_HOST -P $DB_PORT -u $DB_USER --no-create-info $DB_NAME sys_dict sys_config sys_role sys_menu sys_user sys_user_role sys_role_menu > ../sql/base-data.sql
Write-Host "Export completed: base-schema.sql & base-data.sql"
```
- `framework/db-init/scripts/import.ps1`
```
param(
[string]$DB_HOST = "127.0.0.1",
[int]$DB_PORT = 3306,
[string]$DB_NAME = "platform",
[string]$DB_USER = "root",
[string]$DB_PASSWORD = "root"
)
$env:MYSQL_PWD = $DB_PASSWORD
mysql -h $DB_HOST -P $DB_PORT -u $DB_USER $DB_NAME < ../sql/base-schema.sql
mysql -h $DB_HOST -P $DB_PORT -u $DB_USER $DB_NAME < ../sql/base-data.sql
Write-Host "Import completed"
```
## 启动时自动初始化的实现建议(代码思路)
- 创建 `DataInitializer`
- 读取 `app.init.enabled`;若为 `false` 则直接返回。
- 使用 `JdbcTemplate``EntityManager` 查询 `marker-table` 状态。
- 若未初始化:
- 读取并执行 `schema`、`data` 指定的 SQL 文件;分批执行并开启事务。
- 写入标记表 `initialized=true, version=marker-version, ts=now()`
- 并发保护:
- 使用数据库锁或单例启动(例如基于 `SELECT ... FOR UPDATE` 或分布式锁)避免多实例重复初始化。
- 失败回滚与告警:
- 执行失败时回滚事务并记录日志,提示人工介入;避免部分写入。
## 运维与审计
-`sql/base-data.sql` 的修改应评审并走 PR避免带入敏感数据。
- CI 提示:
-`server` 构建流水线中,可增加“初始化脚本语法检查”(如用 `mysql --dry-run` 或解析器)。
- 版本管理:
-`db-init/README.md` 中记录每次更新目的与影响;或使用 `Flyway` 版本号管理。
## 下一步落地
- 我可以为你:
- 搭建 `framework/db-init` 目录与示例脚本、README。
- 在后端新增 `DataInitializer` 组件与配置项,支持 `dev/server` 下自动初始化。
- 可选集成 `Flyway`,将初始化脚本迁移为 `V1__base.sql` 并接入 CI。