简介
本指南面向数据库管理员与运维工程师,系统化说明 DouPHP 的数据迁移策略、工具使用与执行流程。内容覆盖版本控制与增量升级、回滚机制、迁移脚本编写规范(SQL 标准格式、错误处理、事务管理)、执行流程(环境准备、备份、执行监控、结果验证)、复杂场景(结构变更、数据转换、数据清洗),以及自动化脚本与故障恢复策略。
更新 完全移除了upgrade/目录下的升级系统,包括版本迁移脚本、变更日志服务和升级界面。同时更新了支付对账抽奖服务的锁文件路径从storage/cache迁移到storage/state的说明。传统的模块级升级机制仍然保留,支持通过_update/action.php进行模块级别的升级操作。
项目结构
DouPHP 的数据迁移相关能力主要分布在以下位置:
传统模块级升级
- 模块升级入口:每个模块的 _update/action.php 负责按版本条件加载并执行该模块的 SQL/PHP 升级脚本
- 升级脚本:upgrade/data/sql/、upgrade/data/php/、upgrade/data/txt/ 分别存放SQL脚本、PHP逻辑和变更说明
智能存储目录结构
- 运行时状态目录:storage/state/ 存放需要持久化的运行时状态文件
- 临时载荷目录:storage/tmp/ 存放短生命周期的工作文件
- 安装域目录:storage/install/ 管理安装相关的包、会话和记录
- 缓存目录:storage/cache/ 存放可重建的缓存文件
graph TB
A["模块升级入口<br/>_update/action.php"] --> B["模块升级脚本<br/>data/upgrade.sql / upgrade.php"]
C["后台备份控制器<br/>BackupController"] --> D["备份服务<br/>BackupService"]
D --> E["存储目录<br/>storage/backup/*.sql/.zip"]
F["一次性迁移工具<br/>migrate_data_to_storage.php"] --> G["模块目录<br/>MODULE_PATH/<m>/data -> storage"]
H["智能存储修剪<br/>remove.php"] --> I["storage目录结构<br/>state/tmp/install/cache"]
J["支付对账锁<br/>PaymentReconciliationLottery"] --> K["state/payment_reconcile.lock"]
L["限流存储<br/>AbstractThrottleMiddleware"] --> M["state/throttle/"]
N["未安装拦截<br/>bootstrap.php"] --> O["三级判定链<br/>state → storage根 → data"]
图表来源
- action.php(模块升级入口):31-51
- PaymentReconciliationLottery.php:156-169
- AbstractThrottleMiddleware.php:121-126
- bootstrap.php:42-60
章节来源
- action.php(模块升级入口):31-51
核心组件
传统模块级升级组件
- 模块升级入口:根据客户端版本与最低要求版本对比,决定是否执行模块的 SQL/PHP 升级脚本,并在完成后清理缓存
- 备份服务:实现分卷 SQL 导出、ZIP 打包(含 images)、多轮续传、导入、删除、流式下载;内置文件名白名单校验与安全解压规则
- 一次性迁移工具:对 MODULE_PATH 下所有模块进行"仅保留 data"的顶层清理,并将 data 重命名为 storage;支持预览与执行两种模式,具备幂等性约束与错误统计
智能存储管理组件
- 支付对账锁管理:PaymentReconciliationLottery将锁文件从cache/迁移到state/目录
- 限流存储管理:AbstractThrottleMiddleware使用storage/state/throttle/目录存储限流计数器
- 未安装拦截逻辑:bootstrap.php支持三级判定链(state → storage 根 → data)
章节来源
- action.php(模块升级入口):31-51
- PaymentReconciliationLottery.php:156-169
- AbstractThrottleMiddleware.php:121-126
- bootstrap.php:42-60
架构总览
下图展示从"模块升级入口"到"升级执行"再到"智能存储管理"的整体协作关系。
sequenceDiagram
participant Module as "模块升级入口"
participant Script as "升级脚本"
participant Storage as "智能存储管理"
participant Payment as "支付对账锁"
participant Throttle as "限流存储"
participant Bootstrap as "未安装拦截"
Module->>Script : 检查版本并执行升级
Script->>Storage : 维护storage目录结构
Payment->>Storage : 管理state/payment_reconcile.lock
Throttle->>Storage : 管理state/throttle/目录
Bootstrap->>Storage : 三级判定安装状态
图表来源
- action.php(模块升级入口):31-51
- PaymentReconciliationLottery.php:156-169
- AbstractThrottleMiddleware.php:121-126
- bootstrap.php:42-60
详细组件分析
传统模块级升级(_update/action.php)
- 版本判断:读取当前站点版本号后8位与模块要求的最低版本对比,满足条件才执行升级
- 升级脚本加载:优先执行 data/upgrade.sql(自动替换表前缀),再执行 data/upgrade.php(复杂逻辑)
- 后置处理:升级完成后清理缓存目录,确保新结构生效
flowchart TD
Start(["进入模块升级"]) --> ReadVer["读取客户端版本"]
ReadVer --> Check{"是否大于最低版本?"}
Check -- 否 --> End(["结束"])
Check -- 是 --> LoadSQL["加载并执行 upgrade.sql"]
LoadSQL --> LoadPHP["加载并执行 upgrade.php"]
LoadPHP --> ClearCache["清理缓存目录"]
ClearCache --> End
图表来源
- action.php(模块升级入口):31-51
章节来源
- action.php(模块升级入口):31-51
支付对账锁管理
支付对账锁文件从cache/迁移到state/:
- 锁文件位置:state/payment_reconcile.lock
- 锁机制:使用flock实现进程间互斥
- 零字节长驻:锁文件为0字节,锁态在内核内存中
- 自动重建:删除后会重新创建,但可能导致竞态条件
flowchart TD
Start(["支付对账触发"]) --> ResolveDir["解析锁目录"]
ResolveDir --> CheckState{"STORAGE_PATH存在?"}
CheckState -- 是 --> UseState["使用storage/state/"]
CheckState -- 否 --> UseTemp["使用sys_get_temp_dir()"]
UseState --> CreateLock["创建锁文件"]
UseTemp --> CreateLock
CreateLock --> AcquireLock["获取文件锁"]
AcquireLock --> ExecuteTask["执行对账任务"]
ExecuteTask --> ReleaseLock["释放锁"]
ReleaseLock --> End(["完成"])
图表来源
- PaymentReconciliationLottery.php:156-169
章节来源
- PaymentReconciliationLottery.php:156-169
限流存储管理
限流计数器存储在storage/state/throttle/目录:
- 存储路径:AbstractThrottleMiddleware默认使用storage/state/throttle/作为参数
- 配置覆盖:可通过security.throttle.store配置项自定义路径
- 文件命名:每个限流键对应一个JSON文件,文件名为md5(key).json
- 数据结构:{count: int, reset: timestamp}
章节来源
- AbstractThrottleMiddleware.php:121-126
未安装拦截逻辑
bootstrap.php实现了三级判定链来检测安装状态:
- 优先级顺序:storage/state/install.lock → storage/install.lock → data/install.lock
- 安装页面保护:install目录下的请求不受拦截限制
- 自动跳转:未安装时自动跳转到安装页面
flowchart TD
Start(["应用启动"]) --> CheckState["检查storage/state/install.lock"]
CheckState -- 存在 --> InstallOK["已安装"]
CheckState -- 不存在 --> CheckRoot["检查storage/install.lock"]
CheckRoot -- 存在 --> InstallOK
CheckRoot -- 不存在 --> CheckData["检查data/install.lock"]
CheckData -- 存在 --> InstallOK
CheckData -- 不存在 --> CheckInstallPage{"是否在install页面?"}
CheckInstallPage -- 是 --> AllowAccess["允许访问"]
CheckInstallPage -- 否 --> Redirect["重定向到安装页面"]
图表来源
- bootstrap.php:42-60
章节来源
- bootstrap.php:42-60
依赖关系分析
- 模块升级入口:依赖配置中心获取版本信息,依赖数据库层执行 SQL,依赖文件系统清理缓存
- 支付对账锁:依赖flock文件和STORAGE_PATH常量
- 限流存储:依赖AbstractThrottleMiddleware类和storage/state/throttle/目录
- 未安装拦截:依赖bootstrap.php中的STORAGE_PATH常量和三级判定逻辑
graph LR
A["模块升级入口"] --> B["数据库层"]
A --> C["配置中心"]
A --> D["文件系统"]
E["支付对账锁"] --> F["flock"]
E --> G["STORAGE_PATH"]
H["限流存储"] --> I["AbstractThrottleMiddleware"]
H --> J["state/throttle/"]
K["未安装拦截"] --> L["bootstrap.php"]
K --> M["STORAGE_PATH"]
图表来源
- action.php(模块升级入口):31-51
- PaymentReconciliationLottery.php:156-169
- AbstractThrottleMiddleware.php:121-126
- bootstrap.php:42-60
章节来源
- action.php(模块升级入口):31-51
- PaymentReconciliationLottery.php:156-169
- AbstractThrottleMiddleware.php:121-126
- bootstrap.php:42-60
性能考虑
- 模块升级优化:仅在满足版本条件时执行升级脚本,避免不必要的I/O操作
- 锁文件优化:payment_reconcile.lock使用内核级flock,避免用户态文件竞争
- 限流存储优化:AbstractThrottleMiddleware使用文件锁确保并发安全,机会式清理避免频繁IO操作
- 未安装拦截优化:三级判定链快速检测安装状态,减少文件系统查询次数
故障处理与恢复指南
模块升级故障处理
- 前置检查:确认模块的_minimum_version_number设置正确
- 脚本权限:确保data/upgrade.sql和data/upgrade.php具有正确的读写权限
- 缓存清理:升级失败后手动清理cache目录,确保新结构生效
- 版本兼容性:检查客户端版本与模块最低版本要求的兼容性
支付对账锁故障处理
- 锁文件位置:确认锁文件位于storage/state/payment_reconcile.lock
- 锁冲突解决:如果发生锁冲突,重启服务或手动删除锁文件
- 目录权限:确保storage/state/目录具有正确的写权限
- 异常处理:任何异常都会被捕获,不影响主请求流程
限流存储故障处理
- 存储路径:检查storage/state/throttle/目录是否存在且可写
- 配置文件:如使用自定义路径,确认security.throttle.store配置正确
- 文件清理:定期清理过期的限流文件,避免目录无限增长
未安装拦截故障处理
- 安装状态检测:确认storage/state/install.lock文件存在
- 权限问题:确保storage/state/目录具有正确的读写权限
- 安装页面访问:确认install目录下的请求不被拦截
章节来源
- action.php(模块升级入口):31-51
- PaymentReconciliationLottery.php:156-169
- AbstractThrottleMiddleware.php:121-126
- bootstrap.php:42-60
结论
DouPHP 的数据迁移体系由"传统模块级升级 + 智能存储管理"构成,保持了简洁性和可靠性。虽然完全移除了upgrade/目录下的升级系统,但传统的_update/action.php机制仍然有效,支持模块级别的升级需求。通过严格的文件名校验、锁机制和三级判定逻辑,提供了可靠的迁移与状态管理能力。
更新 完全移除了upgrade/目录下的升级系统,简化了整体架构。同时更新了支付对账抽奖服务的锁文件路径从storage/cache迁移到storage/state,提升了系统的稳定性和可维护性。传统的模块级升级机制继续发挥作用,确保了现有功能的向后兼容性。
附录:迁移脚本编写规范与最佳实践
传统模块级升级规范(_update/action.php)
- 版本控制:在模块 _update/action.php 中维护 minimum_version_number,确保只在满足条件时执行升级
- 脚本组织:升级脚本放置于模块 data/ 目录下:upgrade.sql(DDL/DML)与 upgrade.php(复杂逻辑)
- 前缀处理:SQL 脚本应使用表前缀占位符,由入口统一替换,避免硬编码
SQL标准格式
- 事务包裹:使用事务包裹关键 DML,确保原子性;失败时回滚
- 兼容性处理:对日期时间列的空值与零日期进行兼容处理,避免严格模式下导入失败
- 批量操作:批量插入时注意分卷与内存占用,避免超时与 OOM
- 索引优化:先删除旧索引,再添加新索引,避免锁竞争
智能存储目录管理规范
- 目录职责分离:
- state/:存放需要持久化的运行时状态文件
- tmp/:存放短生命周期的临时文件
- install/:管理安装相关的包、会话和记录
- cache/:存放可重建的缓存文件
- 文件迁移规则:
- 从storage根迁移到state/:install.lock、quick.start.dou、payment_reconcile.lock
- 从cache/迁移到tmp/:admin_dirrelocate{token}.php等临时文件
- 从storage/installed/迁移到storage/install/records/:*.installed.php
支付对账锁管理规范
- 锁文件位置:state/payment_reconcile.lock
- 锁机制:使用flock实现进程间互斥,避免竞态条件
- 零字节长驻:锁文件为0字节,锁态在内核内存中
- 自动重建:删除后会重新创建,但可能导致竞态条件
限流存储管理规范
- 存储路径:AbstractThrottleMiddleware使用storage/state/throttle/目录
- 配置覆盖:可通过security.throttle.store配置项自定义路径
- 文件命名:每个限流键对应md5(key).json文件
- 数据结构:{count: int, reset: timestamp}
未安装拦截管理规范
- 三级判定链:storage/state/install.lock → storage/install.lock → data/install.lock
- 安装页面保护:install目录下的请求不受拦截限制
- 自动跳转:未安装时自动跳转到安装页面
错误处理
- 异常捕获:捕获异常并记录日志;对不可恢复错误给出明确提示与回滚指引
- 文件操作:对文件操作(读写、解压)进行存在性与权限检查,失败时中止并告警
- 网络容错:外部API调用失败不应阻塞主流程,应提供降级方案
事务管理
- 显式事务:对跨表更新、关联数据迁移使用显式事务;提交前进行一致性校验
- 长事务优化:长事务需评估锁竞争与锁等待,必要时拆分为小批次
- 回滚策略:确保所有事务都有明确的回滚路径
执行流程
- 环境准备:确认数据库连接、字符集、时区与磁盘空间
- 备份策略:执行全量或增量备份,必要时打包 images
- 执行监控:观察分卷进度、错误日志与审计日志
- 结果验证:核对关键表行数、索引、外键与业务指标
复杂场景处理
- 数据结构变更:先新增字段/表,再逐步迁移数据,最后删除旧字段/表
- 数据转换:在 PHP 侧进行清洗与映射,分批写入目标表,避免一次性加载
- 数据清洗:建立清洗规则与校验清单,对异常数据进行隔离与修复
- 零日期处理:使用专门的函数清洗历史零日期数据,确保与新版本的严格模式兼容
工具与自动化
- 模块升级:继续使用_update/action.php进行模块级升级
- 备份恢复:使用 BackupService 提供的接口进行备份/导入/下载/删除,结合 CI/CD 实现自动化
- 存储修剪:使用 remove.php 工具进行智能存储目录清理,支持预览和执行模式
- 锁文件管理:监控state/payment_reconcile.lock的状态,处理可能的竞态条件
- 限流存储管理:定期检查storage/state/throttle/目录,清理异常的JSON文件
故障恢复
- 升级失败:一旦升级失败,立即从最近备份恢复;若 ZIP 包包含 images,一并还原
- 代码回退:对无法恢复的问题,定位日志并回退代码与脚本,重新演练
- 版本回滚:通过备份恢复到升级前的状态,确保业务连续性
- 存储结构修复:使用remove.php工具重新整理storage目录结构
- 锁文件冲突解决:重启服务或手动删除payment_reconcile.lock后重建
章节来源
- action.php(模块升级入口):31-51
- PaymentReconciliationLottery.php:156-169
- AbstractThrottleMiddleware.php:121-126
- bootstrap.php:42-60