分享mysql数据库自动备份脚本(本机和docker都可用)
利用系统的定时任务周期性执行
备份mysql中的数据
备份策略:
最近30天(每天1份)
最近24小时(每小时1份)
关键点
DB_NAME
: 备份的数据库名DB_USER
: 数据库账号DB_PASS
: 数据库密码
本地部署的mysql
DUMP
: 本机mysqldump
路径
使用mysqldump备份
$DUMP -u$DB_USER -p$DB_PASS $DB_NAME --default-character-set=utf8 --opt -Q -R ->-skip-lock-tables> $OUT_SQL
docker部署的mysql
DOCKER_CONTAINER
: docker容器名
调用docker中的mysqldump备份
docker exec -i "$DOCKER_CONTAINER" mysqldump \-u"$DB_USER" -p"$DB_PASS" \--single-transaction \--skip-lock-tables \--no-tablespaces \"$DB_NAME" > "$OUT_SQL"
下面是脚本源码
修改自己的数据库账号密码和备份路径
#!/bin/sh
DUMP=/usr/bin/mysqldump #mysqldump备份程序执行路径(方案A)
DOCKER_CONTAINER="mysql8" # MySQL 容器名称(方案B)OUT_DIR=/home/developer/mysqlBak #备份文件存放路径
LINUX_USER=root #系统用户名
DB_NAME=user #要备份的数据库名字
DB_USER=mysql #数据库账号
DB_PASS='123456' #数据库密码
DAYS=30 #DAYS=30代表删除30天前的备份,即只保留最近30天的备份cd $OUT_DIR #进入备份存放目录
DATE=`date +%Y_%m_%d_%H` #获取当前系统时间
OUT_SQL="$DATE.sql" #备份数据库的文件名
TAR_SQL="mysqldata_$DATE.tar.gz" #最终保存的数据库备份文件名## 方案A: 下面这行是用本机的mysqldump来备份的
#$DUMP -u$DB_USER -p$DB_PASS $DB_NAME --default-character-set=utf8 --opt -Q -R --skip-lock-tables> $OUT_SQL #备份## 方案B: 下面这行是通过docker exec的方式来备份
# 通过 docker exec 执行 mysqldump(安全方式)
docker exec -i "$DOCKER_CONTAINER" mysqldump \-u"$DB_USER" -p"$DB_PASS" \--single-transaction \--skip-lock-tables \--no-tablespaces \"$DB_NAME" > "$OUT_SQL"# 检查备份是否成功
if [ $? -ne 0 ]; thenecho "MySQL backup failed!"rm -f "$OUT_SQL"exit 1
fitar -czf $TAR_SQL ./$OUT_SQL #压缩为.tar.gz格式
rm $OUT_SQL #删除.sql格式的备份文件
# chown $LINUX_USER:$LINUX_USER $OUT_DIR/$TAR_SQL #更改备份数据库文件的所有者# 获取所有备份文件的日期(去重) - 修复正则表达式匹配下划线格式# 清理策略:保留当天所有备份 + 30天内每日最新备份
TODAY=$(date +%Y%m%d)
echo "开始清理备份,当天日期: $TODAY"# 获取所有备份文件的日期(去重) - 修复正则表达式匹配下划线格式
dates=$(find "$OUT_DIR" -maxdepth 1 -name "mysqldata_*.tar.gz" -type f | \sed -n 's/.*mysqldata_\([0-9]\{4\}\)_\([0-9]\{2\}\)_\([0-9]\{2\}\)_.*/\1\2\3/p' | sort -u)echo "找到的备份日期: $dates"# 对每个日期处理:非当天的每天只保留最新备份
for date in $dates; doecho "处理日期: $date"if [ "$date" = "$TODAY" ]; thenecho " 跳过当天备份: $date"continuefi# 将YYYYMMDD格式转换为YYYY_MM_DD格式进行文件查找year=$(echo $date | cut -c1-4)month=$(echo $date | cut -c5-6)day=$(echo $date | cut -c7-8)date_pattern="${year}_${month}_${day}"echo " 查找日期模式 $date_pattern 的所有备份文件..."files_with_time=$(find "$OUT_DIR" -maxdepth 1 -name "mysqldata_${date_pattern}_*.tar.gz" -type f -printf "%T@ %p\n")echo " 找到的文件: $files_with_time"if [ -z "$files_with_time" ]; thenecho " 该日期没有备份文件"continuefi# 统计文件数量file_count=$(echo "$files_with_time" | wc -l)echo " 该日期共有 $file_count 个备份文件"if [ "$file_count" -gt 1 ]; thenecho " 开始删除旧备份,保留最新的..."echo "$files_with_time" | sort -n | head -n -1 | while read -r timestamp file; doif [ -n "$file" ]; thenecho " 删除文件: $file"rm -v "$file"elseecho " 文件路径为空,跳过"fidone# 显示保留的文件latest_file=$(echo "$files_with_time" | sort -n | tail -1 | awk '{print $2}')echo " 保留最新备份: $latest_file"elseecho " 该日期只有1个备份文件,无需清理"fiecho " ----"
doneecho "开始删除30天前的备份..."
old_files=$(find "$OUT_DIR" -name "mysqldata_*" -type f -mtime +$DAYS)
if [ -n "$old_files" ]; thenecho "30天前的备份文件:"echo "$old_files"find "$OUT_DIR" -name "mysqldata_*" -type f -mtime +$DAYS -exec rm -v {} \;
elseecho "没有找到30天前的备份文件"
fiecho "备份清理完成"