一、备份脚本
bash
#!/bin/bash
# === 配置部分 ===
BACKUP_BASE_DIR="/data/backup_mysql"
DATE=$(date +%F)
LOG_FILE="${BACKUP_BASE_DIR}/logs/backup-${DATE}.log"
LOCK_FILE="/tmp/mysql_backup.lock"
# 备份选项(1=启用,0=禁用)
ENABLE_FULL_BACKUP=1
ENABLE_PER_DB_BACKUP=1
# === 日志重定向 ===
mkdir -p "${BACKUP_BASE_DIR}/logs"
exec >> "$LOG_FILE" 2>&1
echo "===== MySQL Backup Started: $(date) ====="
# === 加锁,避免重复执行 ===
exec 9>"$LOCK_FILE"
if ! flock -n 9; then
echo "❗️ 另一个备份任务正在运行,退出..."
exit 1
fi
# === 全量备份 ===
if [ "$ENABLE_FULL_BACKUP" -eq 1 ]; then
echo "📦 开始全库备份..."
FULL_BACKUP_FILE="${BACKUP_BASE_DIR}/all/all-databases-${DATE}.sql"
FULL_GZ_FILE="${FULL_BACKUP_FILE}.gz"
mkdir -p "${BACKUP_BASE_DIR}/all"
mysqldump --all-databases --single-transaction --quick --lock-tables=false > "$FULL_BACKUP_FILE"
if [ $? -eq 0 ]; then
echo "✔ 全库备份成功: $FULL_BACKUP_FILE"
gzip "$FULL_BACKUP_FILE"
if [ $? -eq 0 ]; then
echo "✔ 全库压缩成功: $FULL_GZ_FILE"
else
echo "✘ 全库压缩失败: $FULL_BACKUP_FILE" >&2
fi
else
echo "✘ 全库备份失败" >&2
rm -f "$FULL_BACKUP_FILE"
fi
fi
# === 每库备份 ===
if [ "$ENABLE_PER_DB_BACKUP" -eq 1 ]; then
echo "📂 开始库级别备份..."
databases=$(mysql -e "SHOW DATABASES;" | grep -Ev "^(Database|information_schema|performance_schema|mysql|sys)$")
for db in $databases; do
echo "🔄 正在备份: $db"
DB_BACKUP_DIR="${BACKUP_BASE_DIR}/${db}"
mkdir -p "$DB_BACKUP_DIR"
DB_BACKUP_FILE="${DB_BACKUP_DIR}/${db}-${DATE}.sql"
DB_GZ_FILE="${DB_BACKUP_FILE}.gz"
mysqldump --single-transaction --quick --lock-tables=false "$db" > "$DB_BACKUP_FILE"
if [ $? -eq 0 ]; then
echo "✔ 备份成功: $DB_BACKUP_FILE"
gzip "$DB_BACKUP_FILE"
if [ $? -eq 0 ]; then
echo "✔ 压缩成功: $DB_GZ_FILE"
else
echo "✘ 压缩失败: $DB_BACKUP_FILE" >&2
fi
else
echo "✘ 备份失败: $db" >&2
rm -f "$DB_BACKUP_FILE"
fi
done
fi
# === 清理过期文件(.sql / .sql.gz) ===
echo "🧹 清理 7 天前的备份文件..."
find "$BACKUP_BASE_DIR" -type f \( -name "*.sql" -o -name "*.sql.gz" \) -mtime +7 -exec rm -f {} \;
echo "===== MySQL Backup Completed: $(date) ====="
二、环境信息
-
服务器主机名:
-
服务器 IP:
-
数据库类型:MySQL
-
MySQL 版本:
8.0.42 Community Server -
目标数据库:
imip_ecb -
数据库字符集:
utf8mb4 -
排序规则:
utf8mb4_general_ci -
备份文件路径(恢复来源):
/data/backup_mysql/imip_ecb/imip_ecb-2025-12-11.sql.gz -
恢复前保护性备份路径:
/data/backup_mysql/manual_before_restore/imip_ecb-before-restore-2025-12-11.sql -
恢复类型:覆盖源库恢复(在同一实例上,用备份覆盖原有 imip_ecb 库)
三、实际恢复操作步骤
1. 查询 imip_ecb 数据库字符集与排序规则
sql
mysql -u root -p -e "
SELECT SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
FROM information_schema.SCHEMATA
WHERE SCHEMA_NAME='imip_ecb';
"
查询结果:
sql
SCHEMA_NAME | DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME
----------- | -------------------------- | ------------------------
imip_ecb | utf8mb4 | utf8mb4_general_ci
目的:记录当前库的字符集/排序规则,确保重建数据库时保持一致。
2. 创建"恢复前快照"备份目录
bash
mkdir -p /data/backup_mysql/manual_before_restore
目的:单独存放本次覆盖前的手工备份,便于必要时回滚。
3. 对覆盖前的 imip_ecb 做一次完整逻辑备份
bash
mysqldump --single-transaction --quick --lock-tables=false \
imip_ecb > /data/backup_mysql/manual_before_restore/imip_ecb-before-restore-`date +%F`.sql
确认备份文件存在:
bash
cd /data/backup_mysql/manual_before_restore
ll
# imip_ecb-before-restore-2025-12-11.sql
目的:为本次覆盖恢复保留一份"恢复前状态"的 SQL 备份。
4. 删除原有 imip_ecb 数据库(为覆盖恢复做准备)
bash
mysql -u root -p -e "DROP DATABASE IF EXISTS imip_ecb;"
目的:清理旧库,避免恢复过程中与原有对象冲突,确保是"重建 + 导入"的干净覆盖。
5. 按原字符集/排序规则重建 imip_ecb 数据库
bash
mysql -u root -p -e "
CREATE DATABASE imip_ecb
DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci;
"
目的:与恢复前字符集/排序规则保持一致,避免编码相关问题。
6. 使用 2025-12-11 备份文件对 imip_ecb 进行覆盖恢复
bash
zcat /data/backup_mysql/imip_ecb/imip_ecb-2025-12-11.sql.gz \
| mysql -u root -p imip_ecb
目的:通过 zcat 解压 .sql.gz,并通过管道将逻辑备份数据导入到新建的 imip_ecb 库,实现在源实例上的覆盖恢复。
7. 恢复后检查:确认数据库存在
bash
mysql -u root -p -e "SHOW DATABASES LIKE 'imip_ecb';"
8. 恢复后检查:确认业务表已成功恢复
bash
mysql -u root -p -D imip_ecb -e "SHOW TABLES;"
输出包含业务表,例如:
bash
EMS_EQUIPMENT_INFO
EMS_INSPECT_TASK
EMS_MAINTENANCE_WORK_ORDER
ERP_STOCK
ERP_STOCK_IN
ERP_STOCK_OUT
ERP_SUPPLIER
ERP_WAREHOUSE
infra_task_attachment
...
目的:确认 EMS/ERP 相关业务表均已从备份中成功恢复,库结构完整。