Docker MySQL 备份与恢复指南,讲解容器内MySQL数据库定时备份、导出导入、快照备份、数据恢复实操步骤,包含docker命令脚本与常见问题排查。
如果要查看怎么用docker安装mysql请查看https://blog.zerosea.cn/install-mysql-with-docker
备份整个数据库
温馨提示
出现以下错误时,
mysqldump: [Warning] Using a password on the command line interface can be insecure.
因为新版本的mysql(MySQL 5.6、5.7、8.0 及以后)不推荐在命令行中直接使用密码 执行的时候加个-i参数从提示符读取密码,下面所有命令都可以这么操作
docker exec -i mysql容器名 mysqldump -u用户名 -p 数据库名 > 数据库备份.sql
方法一:使用 mysqldump 备份整个数据库
# 备份整个数据库(包含所有表的结构和数据)
docker exec mysql容器名 mysqldump -u用户名 -p密码 数据库名 > 数据库备份.sql
# 示例
docker exec mysql_container mysqldump -uroot -p123456 mydatabase > mydatabase_backup.sql
# 仅备份数据库结构(不包含数据)
docker exec mysql容器名 mysqldump -u用户名 -p密码 -d 数据库名 > 数据库结构备份.sql
# 仅备份数据库数据(不包含结构)
docker exec mysql容器名 mysqldump -u用户名 -p密码 -t 数据库名 > 数据库数据备份.sql
方法二:备份所有数据库
# 备份MySQL服务器上的所有数据库
docker exec mysql容器名 mysqldump -u用户名 -p密码 --all-databases > 所有数据库备份.sql
# 排除某些数据库(如系统数据库)
docker exec mysql容器名 mysqldump -u用户名 -p密码 --databases db1 db2 db3 > 指定数据库备份.sql
方法三:压缩备份整个数据库
# 备份并压缩数据库
docker exec mysql容器名 mysqldump -u用户名 -p密码 数据库名 | gzip > 数据库备份.sql.gz
# 备份多个数据库并压缩
docker exec mysql容器名 mysqldump -u用户名 -p密码 --databases db1 db2 | gzip > 多数据库备份.sql.gz
恢复整个数据库
方法一:恢复单个数据库
# 创建数据库(如果不存在)
docker exec mysql容器名 mysql -u用户名 -p密码 -e "CREATE DATABASE IF NOT EXISTS 数据库名"
# 恢复数据库
docker exec -i mysql容器名 mysql -u用户名 -p密码 数据库名 < 数据库备份.sql
# 示例
docker exec -i mysql_container mysql -uroot -p123456 mydatabase < ./mydatabase_backup.sql
方法二:恢复所有数据库
# 从包含所有数据库的备份恢复
docker exec -i mysql容器名 mysql -u用户名 -p密码 < 所有数据库备份.sql
# 示例
docker exec -i mysql_container mysql -uroot -p123456 < ./all_databases_backup.sql
方法三:恢复压缩的数据库备份
# 恢复压缩的数据库备份
gunzip < 数据库备份.sql.gz | docker exec -i mysql容器名 mysql -u用户名 -p密码 数据库名
# 恢复压缩的所有数据库备份
gunzip < 所有数据库备份.sql.gz | docker exec -i mysql容器名 mysql -u用户名 -p密码
备份 MySQL 表
方法一:使用 mysqldump 备份表结构和数据
# 备份单个表(包含结构和数据)
docker exec mysql容器名 mysqldump -u用户名 -p密码 数据库名 表名 > 备份文件.sql
# 示例
docker exec mysql_container mysqldump -uroot -p123456 mydatabase users > users_backup.sql
# 仅备份表结构
docker exec mysql容器名 mysqldump -u用户名 -p密码 -d 数据库名 表名 > 结构备份文件.sql
# 仅备份数据(不包含结构)
docker exec mysql容器名 mysqldump -u用户名 -p密码 -t 数据库名 表名 > 数据备份文件.sql
方法三:使用 SQL 查询导出数据
# 使用 SELECT INTO OUTFILE 导出数据(需要在MySQL内执行)
# 首先进入MySQL容器
docker exec -it mysql容器名 mysql -u用户名 -p密码
# 在MySQL中执行
USE 数据库名;
SELECT * FROM 表名 INTO OUTFILE '/tmp/数据导出.csv'
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n';
# 退出MySQL后,将文件复制到主机
docker cp mysql容器名:/tmp/数据导出.csv ./数据导出.csv
方法四:使用 MySQL 客户端导出数据
# 进入MySQL容器
docker exec -it mysql容器名 bash
# 在容器内使用mysql客户端导出数据
mysql -u用户名 -p密码 -e "SELECT * FROM 数据库名.表名" > /tmp/数据导出.txt
# 退出容器并复制文件
exit
docker cp mysql容器名:/tmp/数据导出.txt ./数据导出.txt
方法二:使用 docker exec 和重定向
# 备份表到主机目录
docker exec mysql容器名 mysqldump -u用户名 -p密码 数据库名 表名 > /主机路径/备份文件.sql
# 示例:备份到当前目录
docker exec mysql_container mysqldump -uroot -p123456 mydatabase users > ./users_backup.sql
恢复 MySQL 表
方法一:使用 mysql 命令恢复
# 恢复表(从sql文件)
docker exec -i mysql容器名 mysql -u用户名 -p密码 数据库名 < 备份文件.sql
# 示例
docker exec -i mysql_container mysql -uroot -p123456 mydatabase < ./users_backup.sql
方法二:进入容器内部恢复
# 1. 将备份文件复制到容器中
docker cp 备份文件.sql mysql容器名:/tmp/
# 2. 进入容器
docker exec -it mysql容器名 bash
# 3. 在容器内执行恢复命令
mysql -u用户名 -p密码 数据库名 < /tmp/备份文件.sql
# 4. 退出容器
exit
实用技巧
1. 压缩备份文件
# 备份并压缩
docker exec mysql容器名 mysqldump -u用户名 -p密码 数据库名 表名 | gzip > 备份文件.sql.gz
# 恢复压缩文件
gunzip < 备份文件.sql.gz | docker exec -i mysql容器名 mysql -u用户名 -p密码 数据库名
2. 定时备份脚本
#!/bin/bash
# 数据库定时备份脚本
# 配置变量
CONTAINER_NAME="mysql_container"
DB_USER="root"
DB_PASS="123456"
DB_NAME="mydatabase"
BACKUP_DIR="/path/to/backups"
RETENTION_DAYS=7 # 保留最近7天的备份
# 创建备份目录
mkdir -p $BACKUP_DIR
# 生成带时间戳的备份文件名
BACKUP_FILE="$BACKUP_DIR/${DB_NAME}_backup_$(date +%Y%m%d_%H%M%S).sql"
# 执行备份
docker exec $CONTAINER_NAME mysqldump -u$DB_USER -p$DB_PASS $DB_NAME > $BACKUP_FILE
# 压缩备份文件
gzip $BACKUP_FILE
# 删除超过保留天数的备份文件
find $BACKUP_DIR -name "${DB_NAME}_backup_*.sql.gz" -mtime +$RETENTION_DAYS -delete
# 输出备份信息
echo "Database backup created: ${BACKUP_FILE}.gz"
3. 备份所有数据库的定时脚本
#!/bin/bash
# 所有数据库定时备份脚本
# 配置变量
CONTAINER_NAME="mysql_container"
DB_USER="root"
DB_PASS="123456"
BACKUP_DIR="/path/to/backups"
RETENTION_DAYS=7 # 保留最近7天的备份
# 创建备份目录
mkdir -p $BACKUP_DIR
# 生成带时间戳的备份文件名
BACKUP_FILE="$BACKUP_DIR/all_databases_backup_$(date +%Y%m%d_%H%M%S).sql"
# 备份所有数据库
docker exec $CONTAINER_NAME mysqldump -u$DB_USER -p$DB_PASS --all-databases > $BACKUP_FILE
# 压缩备份文件
gzip $BACKUP_FILE
# 删除超过保留天数的备份文件
find $BACKUP_DIR -name "all_databases_backup_*.sql.gz" -mtime +$RETENTION_DAYS -delete
# 输出备份信息
echo "All databases backup created: ${BACKUP_FILE}.gz"
3. 批量备份多个表
#!/bin/bash
# 定义变量
CONTAINER_NAME="mysql_container"
DB_USER="root"
DB_PASS="123456"
DB_NAME="mydatabase"
TABLES=("users" "products" "orders") # 要备份的表列表
BACKUP_DIR="/path/to/backups"
# 创建备份目录
mkdir -p $BACKUP_DIR
# 备份每个表
for table in "${TABLES[@]}"; do
backup_file="$BACKUP_DIR/${table}_backup_$(date +%Y%m%d_%H%M%S).sql"
docker exec $CONTAINER_NAME mysqldump -u$DB_USER -p$DB_PASS $DB_NAME $table > $backup_file
echo "Backup created: $backup_file"
done
4. 备份查询结果集
# 备份查询结果(特定条件的数据)
docker exec mysql容器名 mysql -u用户名 -p密码 -e "SELECT * FROM 数据库名.表名 WHERE 条件" > 查询结果.csv
# 示例:备份特定日期后的用户数据
docker exec mysql_container mysql -uroot -p123456 -e "SELECT * FROM mydatabase.users WHERE created_at > '2023-01-01'" > recent_users.csv
# 备份关联查询结果
docker exec mysql_container mysql -uroot -p123456 -e "SELECT u.id, u.name, o.order_id FROM users u JOIN orders o ON u.id = o.user_id" > user_orders.csv
5. 将数据导出为 CSV 格式
# 方法一:使用 mysql 客户端和重定向
docker exec mysql容器名 mysql -u用户名 -p密码 数据库名 -e "SELECT * FROM 表名" | sed 's/\t/","/g; s/^/"/; s/$/"/; s/\n//g' > 数据文件.csv
# 方法二:使用 SQL 导出(需要文件权限)
# 首先在MySQL中执行
docker exec -it mysql容器名 mysql -u用户名 -p密码
mysql> USE 数据库名;
mysql> SELECT * FROM 表名 INTO OUTFILE '/tmp/导出文件.csv'
FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n';
# 然后复制文件到主机
docker cp mysql容器名:/tmp/导出文件.csv ./导出文件.csv
6. 导入 CSV 数据到 MySQL
# 方法一:使用 mysqlimport
# 首先将CSV文件复制到容器
docker cp ./数据文件.csv mysql容器名:/tmp/
# 然后在容器内执行导入
docker exec mysql容器名 mysqlimport -u用户名 -p密码 --local 数据库名 /tmp/数据文件.csv
# 方法二:使用 LOAD DATA INFILE
docker exec -it mysql容器名 mysql -u用户名 -p密码
mysql> USE 数据库名;
mysql> LOAD DATA INFILE '/tmp/数据文件.csv' INTO TABLE 表名
FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n';
常见问题与解决方案
1. 权限问题
如果遇到权限错误,确保 MySQL 用户有足够的权限:
-- 在MySQL中授予必要权限
GRANT SELECT, LOCK TABLES ON 数据库名.* TO '用户名'@'%';
FLUSH PRIVILEGES;
2. 字符集问题
备份时指定字符集:
docker exec mysql容器名 mysqldump -u用户名 -p密码 --default-character-set=utf8mb4 数据库名 表名 > 备份文件.sql
3. 大表备份
对于大型表,可以添加以下参数:
# 增加超时时间
docker exec mysql容器名 mysqldump -u用户名 -p密码 --single-transaction --quick 数据库名 表名 > 备份文件.sql
验证备份
检查备份文件大小
ls -lh 备份文件.sql
查看备份文件内容
head -n 20 备份文件.sql
tail -n 20 备份文件.sql
测试恢复(建议在测试环境)
- 创建测试数据库
- 恢复备份到测试数据库
- 检查数据是否完整
最佳实践
- 定期备份:设置定时任务定期备份重要表
- 多地存储:将备份文件存储在不同位置,防止单点故障
- 验证备份:定期验证备份文件的完整性
- 命名规范:使用清晰的命名规则,包含数据库名、表名和备份时间
- 文档记录:记录备份和恢复的详细步骤和注意事项
自动化备份示例(Docker Compose)
示例一:单个数据库自动备份
如果使用 Docker Compose,可以在 docker-compose.yml 中添加备份服务:
version: "3"
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: yourpassword
MYSQL_DATABASE: mydatabase
volumes:
- mysql_data:/var/lib/mysql
mysql-backup:
image: mysql:8.0
depends_on:
- mysql
volumes:
- ./backups:/backups
command: |
sh -c "
while true; do
docker exec mysql mysqldump -uroot -pyourpassword mydatabase > /backups/mydatabase_backup_$(date +%Y%m%d_%H%M%S).sql
find /backups -name 'mydatabase_backup_*.sql' -mtime +7 -delete
sleep 86400
done"
restart: unless-stopped
volumes:
mysql_data:
示例二:所有数据库自动备份
version: "3"
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: yourpassword
volumes:
- mysql_data:/var/lib/mysql
mysql-backup-all:
image: mysql:8.0
depends_on:
- mysql
volumes:
- ./backups:/backups
command: |
sh -c "
while true; do
docker exec mysql mysqldump -uroot -pyourpassword --all-databases | gzip > /backups/all_databases_backup_$(date +%Y%m%d_%H%M%S).sql.gz
find /backups -name 'all_databases_backup_*.sql.gz' -mtime +7 -delete
sleep 86400
done"
restart: unless-stopped
volumes:
mysql_data:
示例三:使用cron进行定时备份
version: "3"
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: yourpassword
MYSQL_DATABASE: mydatabase
volumes:
- mysql_data:/var/lib/mysql
- ./backups:/backups
command: |
sh -c "
# 创建备份脚本
cat > /backup_script.sh << 'EOF'
#!/bin/sh
DATE=\$(date +%Y%m%d_%H%M%S)
mysqldump -uroot -p$$MYSQL_ROOT_PASSWORD $$MYSQL_DATABASE > /backups/mydatabase_backup_\$DATE.sql
gzip /backups/mydatabase_backup_\$DATE.sql
find /backups -name 'mydatabase_backup_*.sql.gz' -mtime +7 -delete
EOF
# 使脚本可执行
chmod +x /backup_script.sh
# 启动MySQL并设置cron任务
docker-entrypoint.sh mysqld &
echo '0 2 * * * /backup_script.sh' > /etc/crontabs/root
crond -f
"
volumes:
mysql_data:
数据备份与迁移专题
导出特定字段数据
# 导出表的特定字段
docker exec mysql容器名 mysql -u用户名 -p密码 -e "SELECT id, name, email FROM 数据库名.表名" > 部分字段.csv
# 导出带有计算的查询结果
docker exec mysql容器名 mysql -u用户名 -p密码 -e "SELECT id, name, COUNT(*) as order_count FROM 数据库名.表名 GROUP BY id" > 统计数据.csv
跨数据库数据迁移
# 从一个MySQL容器导出数据到另一个容器
# 1. 从源容器导出
docker exec source_mysql mysqldump -u用户名 -p密码 -t 源数据库 源表 > data.sql
# 2. 将数据导入目标容器
docker exec -i target_mysql mysql -u用户名 -p密码 目标数据库 < data.sql
# 注意:确保目标表结构与源表兼容,或先创建表结构
大数据量分批导出
# 分批导出大数据量表(每次1000条)
#!/bin/bash
CONTAINER="mysql_container"
DB_USER="root"
DB_PASS="123456"
DB_NAME="mydatabase"
TABLE="large_table"
BATCH_SIZE=1000
OFFSET=0
# 获取总记录数
TOTAL_RECORDS=$(docker exec $CONTAINER mysql -u$DB_USER -p$DB_PASS -e "SELECT COUNT(*) FROM $DB_NAME.$TABLE" | tail -n 1)
# 分批导出
while [ $OFFSET -lt $TOTAL_RECORDS ]; do
docker exec $CONTAINER mysql -u$DB_USER -p$DB_PASS -e "SELECT * FROM $DB_NAME.$TABLE LIMIT $OFFSET, $BATCH_SIZE" > ${TABLE}_part_${OFFSET}.csv
OFFSET=$((OFFSET + BATCH_SIZE))
echo "Exported records up to $OFFSET"
done
数据备份验证
# 验证导出的数据行数
# 1. 统计原表记录数
docker exec mysql容器名 mysql -u用户名 -p密码 -e "SELECT COUNT(*) FROM 数据库名.表名"
# 2. 统计导出文件记录数(不包括标题行)
cat 导出文件.csv | wc -l
# 3. 验证数据一致性(简单示例)
# 比较特定字段的SUM值
ORIGINAL_SUM=$(docker exec mysql容器名 mysql -u用户名 -p密码 -e "SELECT SUM(amount) FROM 数据库名.表名" | tail -n 1)
EXPORTED_SUM=$(cat 导出文件.csv | awk -F',' 'NR>1 {sum+=$3} END {print sum}')
echo "Original sum: $ORIGINAL_SUM, Exported sum: $EXPORTED_SUM"
注意事项
- 备份大型表时可能会占用较多系统资源
- 在备份过程中表可能会被锁定,影响正常业务
- 恢复操作会覆盖现有数据,请谨慎操作
- 恢复前建议先备份当前数据,以防意外
- 导出CSV文件时注意字符编码问题,可能需要指定–default-character-set参数
- 大数据量导出时考虑分批处理,避免内存溢出
- 敏感数据导出时注意数据安全,必要时进行加密处理