# 11.9 备份与恢复 :::danger 生产环境必须备份 数据库和上传文件必须定期备份,建议每天自动备份。备份文件应存储在独立于服务器的安全位置。 ::: ## 数据库备份 ### 手动备份 ```bash # ----------------------------------------------------------------------------- # MySQL 全量备份(结构 + 数据) # ----------------------------------------------------------------------------- # -u root → 数据库用户名 # -proot → 数据库密码(生产环境建议用 -p 后不跟密码,交互式输入) # rxthinkcmf... → 要备份的数据库名 # > backup_*.sql → 输出到文件,$(date +%Y%m%d) 自动生成日期后缀 mysqldump -u root -proot rxthinkcmf.laravel13.elevue > backup_$(date +%Y%m%d).sql # ----------------------------------------------------------------------------- # 压缩备份(推荐 — 可节省 70%+ 磁盘空间) # ----------------------------------------------------------------------------- # | gzip → 将 mysqldump 输出通过管道传给 gzip 压缩 mysqldump -u root -proot rxthinkcmf.laravel13.elevue | gzip > backup_$(date +%Y%m%d).sql.gz # ----------------------------------------------------------------------------- # 仅备份表结构(不含数据 — 用于对比表结构变更) # ----------------------------------------------------------------------------- # --no-data → 只导出 CREATE TABLE 语句,不导出数据 mysqldump -u root -proot --no-data rxthinkcmf.laravel13.elevue > schema_$(date +%Y%m%d).sql # ----------------------------------------------------------------------------- # 仅备份数据(不含表结构 — 用于数据迁移) # ----------------------------------------------------------------------------- # --no-create-info → 只导出 INSERT 语句,不导出 CREATE TABLE mysqldump -u root -proot --no-create-info rxthinkcmf.laravel13.elevue > data_$(date +%Y%m%d).sql ``` :::info 大库提示 本项目初始化数据约 216MB(导出后更大),全量备份建议使用压缩(gzip),并避开业务高峰时段。 ::: ### 自动备份脚本 ```bash #!/bin/bash # ============================================================================= # backup_db.sh — 数据库自动备份脚本 # ============================================================================= # 用途:自动备份 MySQL 数据库,压缩存储,自动清理过期备份 # 用法:crontab 定时调用,或手动执行 bash backup_db.sh # ============================================================================= # ----------------------------------------------------------------------------- # 配置参数(按实际环境修改) # ----------------------------------------------------------------------------- BACKUP_DIR="/backup/mysql" # 备份文件存放目录 DB_NAME="rxthinkcmf.laravel13.elevue" # 要备份的数据库名 DB_USER="root" # 数据库用户名 DB_PASS="root" # 数据库密码 DATE=$(date +%Y%m%d_%H%M%S) # 当前时间戳(年月日_时分秒) KEEP_DAYS=30 # 保留最近 N 天的备份 # ----------------------------------------------------------------------------- # 创建备份目录(-p 参数:目录不存在时自动创建) # ----------------------------------------------------------------------------- mkdir -p $BACKUP_DIR # ----------------------------------------------------------------------------- # 执行备份(mysqldump 输出通过管道传给 gzip 压缩) # ----------------------------------------------------------------------------- mysqldump -u $DB_USER -p$DB_PASS $DB_NAME | gzip > $BACKUP_DIR/backup_$DATE.sql.gz # ----------------------------------------------------------------------------- # 检查备份结果($? 为上一条命令的退出码,0=成功) # ----------------------------------------------------------------------------- if [ $? -eq 0 ]; then echo "[$(date)] 备份成功: backup_$DATE.sql.gz" else echo "[$(date)] 备份失败!" exit 1 # 非零退出码表示失败,便于监控系统捕获 fi # ----------------------------------------------------------------------------- # 清理过期备份 # ----------------------------------------------------------------------------- # find 参数说明: # -name "backup_*.sql.gz" → 匹配备份文件名格式 # -mtime +$KEEP_DAYS → 修改时间超过 N 天的文件 # -delete → 删除匹配的文件 find $BACKUP_DIR -name "backup_*.sql.gz" -mtime +$KEEP_DAYS -delete echo "[$(date)] 清理完成,保留最近 $KEEP_DAYS 天的备份" ``` ### 配置定时备份 ```bash # 编辑当前用户的 crontab 定时任务 crontab -e # ----------------------------------------------------------------------------- # 定时备份规则 # ----------------------------------------------------------------------------- # 格式:分 时 日 月 周 命令 # 0 3 * * * → 每天凌晨 3:00 执行 # 0 4 * * 0 → 每周日凌晨 4:00 执行(0=周日) # >> /var/log/backup.log 2>&1 → 追加日志(2>&1 将错误也写入日志) # ----------------------------------------------------------------------------- 0 3 * * * /www/scripts/backup_db.sh >> /var/log/backup.log 2>&1 0 4 * * 0 /www/scripts/backup_db_full.sh >> /var/log/backup.log 2>&1 ``` ## 上传文件备份 ```bash # ----------------------------------------------------------------------------- # 备份上传目录为压缩包 # ----------------------------------------------------------------------------- # tar 参数说明: # -c → 创建新归档 # -z → 用 gzip 压缩 # -f → 指定输出文件名 # $(date +%Y%m%d) → 自动生成日期后缀 # 本项目上传目录默认在 public/uploads/(FILE_UPLOAD_DIR=uploads) tar -czf /backup/uploads_$(date +%Y%m%d).tar.gz /www/api/public/uploads/ # ----------------------------------------------------------------------------- # 上传文件自动备份脚本 # ----------------------------------------------------------------------------- #!/bin/bash BACKUP_DIR="/backup/uploads" # 备份存放目录 DATE=$(date +%Y%m%d) # 日期后缀 mkdir -p $BACKUP_DIR # 创建目录(如不存在) tar -czf $BACKUP_DIR/uploads_$DATE.tar.gz /www/api/public/uploads/ # 压缩打包 find $BACKUP_DIR -name "uploads_*.tar.gz" -mtime +30 -delete # 清理 30 天前的备份 ``` ## 恢复 ### 恢复数据库 ```bash # ----------------------------------------------------------------------------- # 从 SQL 文件恢复(全量覆盖) # ----------------------------------------------------------------------------- # < backup_*.sql → 将文件内容作为 mysql 命令的输入 mysql -u root -proot rxthinkcmf.laravel13.elevue < backup_20260920.sql # ----------------------------------------------------------------------------- # 从压缩文件恢复(gunzip 解压后传给 mysql) # ----------------------------------------------------------------------------- # gunzip < file.sql.gz → 解压并输出到标准输出 # | mysql → 通过管道传给 mysql 命令执行 gunzip < backup_20260920.sql.gz | mysql -u root -proot rxthinkcmf.laravel13.elevue # ----------------------------------------------------------------------------- # 恢复到新数据库(安全起见 — 先验证再切换) # ----------------------------------------------------------------------------- # 1. 创建临时验证数据库 mysql -u root -proot -e "CREATE DATABASE \`rxthinkcmf.laravel13.elevue_restore\`;" # 2. 恢复备份到临时库 mysql -u root -proot rxthinkcmf.laravel13.elevue_restore < backup_20260920.sql # 3. 验证数据无误后,重命名数据库(需停机操作) ``` :::warning 恢复后清理缓存 恢复数据库后务必执行 `php artisan cache:clear`(或 `php artisan dict:clear-cache`),避免 Redis 中的旧字典/参数缓存与新数据不一致。 ::: ### 恢复上传文件 ```bash # ----------------------------------------------------------------------------- # 恢复上传目录到原始位置 # ----------------------------------------------------------------------------- # tar 参数说明: # -x → 解压归档 # -z → 解压 gzip # -f → 指定归档文件 # -C → 解压到指定目录(/ 表示按归档内的绝对路径还原) tar -xzf /backup/uploads_20260920.tar.gz -C / # ----------------------------------------------------------------------------- # 仅恢复特定子目录(如只恢复文章附件) # ----------------------------------------------------------------------------- # 在归档文件名后追加要解压的路径前缀 tar -xzf /backup/uploads_20260920.tar.gz -C / www/api/public/uploads/article/ ``` ## 备份验证 :::warning 必须定期验证备份 备份文件必须定期恢复验证,确保备份可用。建议每月进行一次恢复测试。 ::: ```bash #!/bin/bash # ============================================================================= # verify_backup.sh — 备份验证脚本 # ============================================================================= # 用途:将备份恢复到临时数据库,验证数据完整性后清理 # 用法:bash verify_backup.sh backup_20260920.sql.gz # ============================================================================= BACKUP_FILE=$1 # 第一个参数:备份文件路径 VERIFY_DB="rxthinkcmf.laravel13.elevue_verify" # 临时验证数据库名 # ----------------------------------------------------------------------------- # 创建验证数据库(先删除旧的,再创建新的) # ----------------------------------------------------------------------------- # DROP DATABASE IF EXISTS → 如果存在则删除(避免同名冲突) mysql -u root -p -e "DROP DATABASE IF EXISTS $VERIFY_DB; CREATE DATABASE $VERIFY_DB;" # ----------------------------------------------------------------------------- # 恢复备份到验证数据库 # ----------------------------------------------------------------------------- gunzip < $BACKUP_FILE | mysql -u root -p $VERIFY_DB # ----------------------------------------------------------------------------- # 验证数据完整性 # ----------------------------------------------------------------------------- # -N → 不输出表头(只输出数据值) # information_schema.tables → MySQL 系统表,存储所有表的元信息 TABLE_COUNT=$(mysql -u root -p -N -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='$VERIFY_DB';") echo "恢复的表数量: $TABLE_COUNT" # 检查用户表数据量(验证核心数据是否完整,注意本项目表前缀为 laravel_) USER_COUNT=$(mysql -u root -p -N -e "SELECT COUNT(*) FROM $VERIFY_DB.laravel_user;") echo "用户数量: $USER_COUNT" # ----------------------------------------------------------------------------- # 清理验证数据库(验证完毕后删除临时库) # ----------------------------------------------------------------------------- mysql -u root -p -e "DROP DATABASE $VERIFY_DB;" echo "备份验证完成" ``` ## 备份存储建议 | 存储方式 | 优点 | 缺点 | |----------|------|------| | 本地磁盘 | 速度快 | 服务器故障可能丢失 | | NAS / 网络存储 | 独立于服务器 | 需要网络 | | 云存储(OSS/S3) | 高可靠、异地 | 需要付费 | | 异地服务器 | 灾难恢复 | 需要维护 | :::tip 最佳实践 - 本地保留最近 7 天的备份 - 异地保留最近 30 天的备份 - 每月进行一次恢复测试 - 备份文件加密存储(如含敏感数据) - 数据库与 `public/uploads/`、`.env` 一并纳入备份范围(.env 单独加密保管) :::