MySQL 8.0 数据库迁移
MySQL 8.0 → MySQL 8.0 数据库迁移
场景:Linux MySQL 8.0 → Windows MySQL 8.0,mysqldump 逻辑导出 + 客户端导入。
同版本之间不需要任何兼容性改写(utf8mb4_0900_*、caching_sha2_password两端都支持)。
配套脚本:export_db.sh(导出用,因为要按规则排除表)。导入只要一行命令。
一、导出脚本(源端)
#!/bin/bash
DB_HOST=""
DB_PORT=""
DB_USER="your_user"
DB_PASS="your_password"
DB_NAME="your_db"
BASE_NAME="your_db_backup"
OUTPUT_DIR="/root"
TIMESTAMP=$(date +"%Y%m%d_%H%M")
OUTPUT="${OUTPUT_DIR}/${BASE_NAME}_${TIMESTAMP}.sql"
# 排除表名含这些子串的表(空格分隔,留空不排除)
EXCLUDE_SUBSTRINGS="_20"
# 连接选项
CONN_OPTS=""
[ -n "$DB_HOST" ] && CONN_OPTS="$CONN_OPTS -h$DB_HOST"
[ -n "$DB_PORT" ] && CONN_OPTS="$CONN_OPTS -P$DB_PORT"
[ -n "$DB_USER" ] && CONN_OPTS="$CONN_OPTS -u$DB_USER"
PASS_OPT=""
[ -n "$DB_PASS" ] && PASS_OPT="-p$DB_PASS"
# 构建排除条件
EXCLUDE_COND=""
if [ -n "$EXCLUDE_SUBSTRINGS" ]; then
CONDITIONS=""
for PAT in $EXCLUDE_SUBSTRINGS; do
if [ -z "$CONDITIONS" ]; then
CONDITIONS="INSTR(TABLE_NAME, '$PAT') > 0"
else
CONDITIONS="$CONDITIONS OR INSTR(TABLE_NAME, '$PAT') > 0"
fi
done
EXCLUDE_COND="AND ($CONDITIONS)"
fi
IGNORE_ARGS=""
if [ -n "$EXCLUDE_COND" ]; then
for TBL in $(mysql $CONN_OPTS $PASS_OPT -N -e \
"SELECT TABLE_NAME FROM information_schema.TABLES
WHERE TABLE_SCHEMA='$DB_NAME' $EXCLUDE_COND;"); do
IGNORE_ARGS="$IGNORE_ARGS --ignore-table=$DB_NAME.$TBL"
done
fi
mysqldump $CONN_OPTS $PASS_OPT \
--single-transaction \
--quick \
--add-drop-table \
--no-tablespaces \
--skip-triggers \
--skip-routines \
--skip-events \
--set-gtid-purged=OFF \
--default-character-set=utf8mb4 \
--net-buffer-length=1M \
--hex-blob \
$IGNORE_ARGS \
--databases $DB_NAME > $OUTPUT
if command -v pigz >/dev/null 2>&1; then
pigz -9 -f "$OUTPUT"
else
gzip -f "$OUTPUT"
fi
参数说明
| 参数 | 说明 |
|---|---|
--single-transaction |
InnoDB 一致性快照,不锁表 |
--quick |
逐行读取,大表不爆内存 |
--hex-blob |
二进制字段输出为 0x...,避免导入时被客户端当命令 |
--set-gtid-purged=OFF |
不写 GTID_PURGED,避免目标端 GTID 冲突 |
--default-character-set=utf8mb4 |
防止中文乱码 |
--net-buffer-length=1M |
单行 INSERT 约 1MB,导入更快 |
--no-tablespaces |
不需要 PROCESS 权限 |
--ignore-table |
排除历史/归档表 |
不要加
--skip-extended-insert:会变成每行一条 INSERT,几百 MB 要导好几天。
二、传输
必须用二进制模式(FTP ASCII、文本模式解压会改坏文件),落地后核对校验值:
md5sum your_db_backup_*.sql.gz
certutil -hashfile ".\your_db_backup.sql" MD5
三、导入(目标端)
一行命令:
C:\Program Files\MySQL\MySQL Server 8.0\bin\mysql.exe --binary-mode --default-character-set=utf8mb4 --max-allowed-packet=512M -u your_user -p -h 127.0.0.1 -P 3306 your_db < "D:\backup\your_db_backup.sql"
Linux:
gunzip -kf your_db_backup.sql.gz
mysql --binary-mode --default-character-set=utf8mb4 --max-allowed-packet=512M \
-u your_user -p -h 127.0.0.1 -P 3306 your_db < your_db_backup.sql
密码由客户端交互提示,不写在命令行、不进历史记录。
参数说明
| 参数 | 说明 |
|---|---|
--binary-mode |
非交互模式下禁用客户端对 \ 命令的解析(关键,见第四节) |
--default-character-set=utf8mb4 |
与导出保持一致 |
--max-allowed-packet=512M |
需大于单行 INSERT;服务端 max_allowed_packet 也要 ≥ 64M |
密码由客户端交互提示,不写在命令行、不进历史记录。
四、常见报错:Unknown command '\''
ERROR at line 4949: Unknown command '\''.
原因:这是 mysql 客户端的错,不是服务端的。非交互模式下客户端仍会把行首的 \ 当客户端命令解析。之所以会走到行首,是因为数据里有未转义的裸二进制字节(0x27 提前闭合了字符串引号)。
--hex-blob 只覆盖 BINARY/VARBINARY/BLOB/BIT/空间类型,覆盖不了 varchar/text 里塞的二进制(序列化串、gzcompress、加密串等)。
解决:导入加 --binary-mode。官方说明:非交互模式下禁用除 charset、delimiter 外的所有客户端命令。
治本:查出把二进制存进文本列的字段,改成 BLOB/VARBINARY,或应用层改存 base64。
SELECT TABLE_NAME, COLUMN_NAME FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA='your_db'
AND DATA_TYPE IN ('char','varchar','tinytext','text','mediumtext','longtext');
SELECT COUNT(*) FROM `表名` WHERE `列名` REGEXP '[[:cntrl:]]';
五、检查清单
如果这篇文章对你有用,可以关注本人微信公众号获取更多ヽ(^ω^)ノ ~


浙公网安备 33010602011771号