利用系统的定时任务周期性执行
备份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 ]; then
    echo "MySQL backup failed!"
    rm -f "$OUT_SQL"
    exit 1
fi


tar -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; do
    echo "处理日期: $date"

    if [ "$date" = "$TODAY" ]; then
        echo "  跳过当天备份: $date"
        continue
    fi

    # 将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" ]; then
        echo "  该日期没有备份文件"
        continue
    fi

    # 统计文件数量
    file_count=$(echo "$files_with_time" | wc -l)
    echo "  该日期共有 $file_count 个备份文件"

    if [ "$file_count" -gt 1 ]; then
        echo "  开始删除旧备份,保留最新的..."
        echo "$files_with_time" | sort -n | head -n -1 | while read -r timestamp file; do
            if [ -n "$file" ]; then
                echo "    删除文件: $file"
                rm -v "$file"
            else
                echo "    文件路径为空,跳过"
            fi
        done

        # 显示保留的文件
        latest_file=$(echo "$files_with_time" | sort -n | tail -1 | awk '{print $2}')
        echo "  保留最新备份: $latest_file"
    else
        echo "  该日期只有1个备份文件,无需清理"
    fi

    echo "  ----"
done

echo "开始删除30天前的备份..."
old_files=$(find "$OUT_DIR" -name "mysqldata_*" -type f -mtime +$DAYS)
if [ -n "$old_files" ]; then
    echo "30天前的备份文件:"
    echo "$old_files"
    find "$OUT_DIR" -name "mysqldata_*" -type f -mtime +$DAYS -exec rm -v {} \;
else
    echo "没有找到30天前的备份文件"
fi

echo "备份清理完成"

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐