# 数据库初始方案(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。