数据迁移(Data Migration) 将数据库系统(包括数据、结构及应用依赖)从源环境安全、一致、高效地转移至目标环境的系统工程。
|----------|---------------|------------------------------|
| 类型 | 说明 | 示例 |
| 同构迁移 | 同类型数据库版本升级 | MySQL 5.7 → 8.0 |
| 异构迁移 | 不同数据库之间迁移 | MySQL → DM8 / MySQL → Oracle |
| 云迁移 | 从本地机房IDC迁往云平台 | 自建机房 → 阿里云 / 华为云 |
常见的升级方案有三种
|-----------|---------------------------|------------|---------|-----|---------------------|
| 方案 | 特点 | 适用场景 | 停机时间 | 复杂度 | 简历体现点 |
| 方案A:原地升级 | 在原服务器上直接升级 MySQL 二进制和数据文件 | 数据量小,允许停机 | 长(4-8h) | 低 | 掌握mysql_upgrade工具使用 |
| 方案B:逻辑迁移 | 导出数据后再导到新版本 | 数据量中等,结构变更 | 中(1-2h) | 中 | mysqldump高级参数调优 |
| 方案C:主从切换 | 使用同步工具 | 大集群,要求高可用 | 短(分钟级) | 高 | 重点掌握,面试加分项 |
环境准备
现在有两台服务器
node1装的是MySQL5.x
node2装的是MySQL8.x
1,两台服务器安装一些依赖包
dnf install vim wget rsync telnet net-tools -y
2,改文件,里面的地址改成自己的,这一块对应的是nmtui那里,改过的可以不用管
vim /etc/NetworkManager/system-connections/ens160.nmconnection
# 分割线 ---- 核心内容如下,把 address 改成 192.168.88.XX ---
[ipv4]
method=manual
address=192.168.88.161/24 # 改成自己的IP
gaetway=192.168.88.2
dns=8.8.8.8;114.114.114.114
[ipv6]
addr-gen-mode=eui64
method=auto
# 分割线 ----
3,修改两个服务器的主机名
hostnamectl set-hostname mysql5-node.itcast.cn && bash
hostnamectl set-hostname mysql8-node.itcast.cn && bash
4,防火墙
systemctl stop firewalld
systemctl disable firewalld
# 临时设置
setenforce 0
永久设置 vim /etc/selinux/config
把22行内容更改如下: 22 SELINUX=disabled
5,重启,虚拟机关机,拍摄快照
# 重启服务器
reboot
# 网卡重启
systemctl restart NetworkManager
nmcli conn down ens160 && nmcli conn up ens160
构造数据
给mysql5.x这个数据库,创建表加入一些数据
drop database if exists db_itheima;
create database db_itheima default charset=utf8;
use db_itheima;
CREATE TABLE tb_users (
user_id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
password VARCHAR(100) NOT NULL,
email VARCHAR(100),
phone VARCHAR(20),
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE tb_goods (
goods_id INT PRIMARY KEY AUTO_INCREMENT,
goods_name VARCHAR(100) NOT NULL,
price DECIMAL(10,2) NOT NULL,
stock INT DEFAULT 0,
category VARCHAR(50),
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE tb_orders (
order_id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
goods_id INT NOT NULL,
quantity INT NOT NULL DEFAULT 1,
total_price DECIMAL(10,2) NOT NULL,
order_time DATETIME DEFAULT CURRENT_TIMESTAMP,
status VARCHAR(20) DEFAULT 'pending',
FOREIGN KEY (user_id) REFERENCES tb_users(user_id),
FOREIGN KEY (goods_id) REFERENCES tb_goods(goods_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO tb_users (username, password, email, phone) VALUES
('alice', '123456', 'alice@example.com', '13800000001'),
('bob', '123456', 'bob@example.com', '13800000002'),
('charlie', '123456', 'charlie@example.com', '13800000003');
INSERT INTO tb_goods (goods_name, price, stock, category) VALUES
('iPhone 15', 6999.00, 20, '手机'),
('MacBook Pro 14', 13999.00, 10, '笔记本'),
('AirPods Pro 2', 1999.00, 30, '耳机'),
('iPad Air', 4599.00, 15, '平板');
INSERT INTO tb_orders (user_id, goods_id, quantity, total_price, status) VALUES
(1, 1, 1, 6999.00, 'paid'),
(2, 3, 2, 3998.00, 'shipped'),
(3, 4, 1, 4599.00, 'pending'),
(1, 2, 1, 13999.00, 'paid');

-----------------------------------------------------以下为同构迁移-------------------------------------------------------
同一款数据库产品之间搬家。源库和目标库数据库引擎完全一样,只是版本、服务器、机房、IP 不一样
方案一:逻辑迁移
[MySQL 5.7 源库]
│
│ ① 全量逻辑备份(mysqldump)
▼
[备份文件 backup.sql]
│
│ ② 传输至目标服务器
▼
[MySQL 8.0 目标库]
│
│ ③ 恢复导入(mysql < backup.sql)
▼
✅ 数据迁移完成
步骤1,全量备份
创建一个存放备份文件的目录
mkdir /backup
cd /backup
导出数据
mysqldump -uroot -p --single-transaction --routines --triggers --events --set-gtid-purged=OFF db_itheima > db_itheima.sql

- -h 主机IP,指向服务器IP
- --routines 备份存储过程和函数,如果不加此参数,存储过程和函数不会备份
- --triggers 备份触发器,默认已包含,但显式指定更安全
- --events 备份事件调度器(定时任务),MySQL 的事件(类似 cron job)
- --set-gtid-purged=OFF GTID 相关:禁用 GTID 信息写入备份文件
参数说明:
|-----------------------|----------------------|
| 参数 | 作用 |
| --single-transaction | 保证一致性备份(适合 InnoDB) |
| --master-data=2 | 记录 binlog 位点(方便后续同步) |
| --routines | 导出存储过程和函数 |
| --events | 导出事件调度器对象 |
| --triggers | 导出触发器 |
| --set-gtid-purged=OFF | 禁止 GTID 自动导入(跨版本推荐) |
| --hex-blob | 二进制字段安全导出 |
| --databases | 可一次导出多个数据库 |
| > /backup/...sql | 输出路径(推荐命名带日期) |
步骤2,同步备份数据
# 在 MySQL 8 服务器上,创建备份目录
mkdir -p /backup/
# 回到 MySQL 5 服务器,同步
scp /backup/db_itheima.sql root@192.168.88.102:/backup/

如果是使用了带建库的命令 比如 mysqldump -B db_itheima > xxx.sql
接收数据的这个服务器就不用建库了 我们用的scp需要手动建库
#装了MySQL8的服务器
create database db_itheima character set utf8mb4 collate utf8mb4_general_ci;
CHARACTER SET utf8mb4使用完整 UTF-8 字符集,支持中文,是 MySQL 5.7 / 8.0 推荐字符集。
COLLATE utf8mb4_general_ci排序规则,ci代表大小写不敏感,ABC和abc会判定为相等。
步骤3,全量恢复
导入 MySQL8 时自动升级元数据结构,确保字符集统一(建议 utf8mb4)
# 恢复指定数据库
mysql -uroot -p db_itheima < /backup/db_itheima.sql
# 或者,使用大文件恢复优化
mysql -uroot -p --init-command="SET autocommit=0; SET foreign_key_checks=0; SET unique_checks=0;" \
< /backup/db_itheima_2025-11-05.sql
说明:禁用外键、唯一检查与自动提交可显著提升导入速度。

校验一下

方案二:主从切换
主从切换(企业生产方案)GTID方式来实现,在确保数据一致性、业务连续性的前提下,平滑地将读写流量从旧主库迁移到新主库
现在已经把两个服务器,还原到刚安装好 MySQL 5.7 和 MySQL 8 的状态
步骤1,配置MySQL核心文件my.cnf
mysql5.x服务器主从 GTID 复制配置
vim /etc/my.cnf 在mysql段落后追加以下内容
server-id = 1
log-bin = /export/server/mysql/data/binlog
binlog_format = STATEMENT
binlog_checksum = NONE
gtid_mode = ON
enforce_gtid_consistency = ON
log_slave_updates = ON
配置完重启一下服务
systemctl restart mysqld
- server-id = 1 给这个服务器的id设为1,主从集群里的服务器id不能重复,一会给另一台设置别的id
- log-bin = /export/server/mysql-5.7/data/binlog 二进制日志的存放路径
- binlog_format = STATEMENT 二进制日志记录格式
二进制日志记录格式(3选1)
STATEMENT(语句模式):只记录执行的 SQL 语句,日志体积小。
ROW(行模式):记录每一行数据的变化,数据最严谨,默认推荐。
MIXED:混合模式。你这里配置的是纯 SQL 语句写入 binlog。
- binlog_checksum = NONE 关闭 binlog 校验,解决跨版本主从复制报错
- gtid_mode = ON开启 GTID 全局事务 ID 模式
- enforce_gtid_consistency = ON 保证所有事务都符合 GTID 规范,打开 GTID 时这一项必须同时开启,否则启动失败
- log_slave_updates = ON 从库在同步完主库 binlog 之后,把同步过来的 SQL 再写入自己的 binlog,一主多从、MGR、双主架构时必须打开

mysql8.x服务器的主从gtid复制配置
vim /etc/my.cnf
server-id = 2
relay_log = /export/server/mysql/data/relaybin
log-bin = /export/server/mysql/data/binlog
binlog_format = STATEMENT
read_only = ON
gtid_mode = ON
enforce_gtid_consistency = ON
master_info_repository = TABLE
relay_log_info_repository = TABLE
-
enforce_gtid_consistency = ON # 确保事务的 GTID 安全性,为 GTID 复制做准备。
-
master_info_repository = TABLE # 将主库连接信息存储在系统表中。
-
relay_log_info_repository = TABLE # 将中继日志应用进度存储在系统表中。
systemctl restart mysqld

步骤2,创建同步账号
在 MySQL 5.7主库上,创建专用复制账号
create user 'replication'@'%' identified by '123456';
grant all on *.* TO 'replication'@'%';
flush privileges;
步骤3,全量同步
确保两个服务器的数据一样,只有主、从初始数据完全一致,binlog 同步过来的新增操作才能正常执行,主从数据才能长期保持一致
MySQL5导出备份文件
mkdir /backup
cd /backup
mysqldump -uroot -p -B --single-transaction --routines --triggers --events --set-gtid-purged=OFF db_itheima > db_itheima.sql

MySQL8这边建一个目录 来存放备份文件 mkdir /backup
MySQL5这边用远程文件拷贝命令把数据拷贝过去
scp /backup/db_itheima.sql root@192.168.88.102:/backup/

MySQL8导入
mysql -uroot -p < /backup/db_itheima.sql

步骤4,主从同步
从服务器,也就是MySQL8的服务器操作
CHANGE MASTER TO
MASTER_HOST='192.168.88.101',
MASTER_USER='replication',
MASTER_PASSWORD='123456',
MASTER_AUTO_POSITION=1;
START SLAVE;
SHOW SLAVE STATUS\G

如果不是俩yes
检擦是不是uuid没删,
-
关闭 MySQL 服务
-
删除从库的
auto.cnf -
重启 MySQL,数据库会自动重新生成全新的 UUID。
stop slave;
reset slave all;CHANGE MASTER TO
MASTER_HOST='192.168.88.101',
MASTER_USER='replication',
MASTER_PASSWORD='123456',
MASTER_AUTO_POSITION=1;
插入一条信息测试一下

在全量迁移完成后,为了保持实时一致,可使用以下工具之一:
|-------------|------------------------------|-----------|
| 工具 | 特点 | 推荐场景 |
| Canal | 监听 MySQL5 binlog → 写入 MySQL8 | 内网迁移、稳定可控 |
| DTS | 云端迁移服务(支持 MySQL → MySQL) | 云上场景 |
| Debezium | Kafka/Connector 增量同步 | 大型微服务架构 |
| Replication | 原生主从复制方式 | 简单架构迁移 |
三种校验方式:
|-------------------|---------------------------|-------------------------------------------------|
| 工具 | 功能 | 示例 |
| pt-table-checksum | 比对主从差异 | pt-table-checksum --replicate=percona.checksums |
| pt-table-sync | 自动修复差异数据 | pt-table-sync --execute |
| 自定义SQL | COUNT / SUM / CHECKSUM 校验 | 比较记录数和聚合值 |
步骤5,主从切换(目前不能实现)
要实现自动切换,必须额外部署中间件:Keepalived(VIP 虚拟 IP)、Orchestrator、MGR 集群。只靠单纯主从复制,只能手动切换,无法自动容灾。
- 停止业务写入旧库;
- 等待同步延迟为 0;
- 切换应用连接到新库;
- 保留旧库为回滚备份(7 天以上)。
1. 停止业务写入旧库
-
操作:把应用的写入请求暂时拦截,不再向原主库执行 INSERT/UPDATE/DELETE。
-
目的:不再产生新的 binlog 事务,保证增量数据不再增加。
#旧主库锁库禁止写入
flush tables with read lock;
2. 等待同步延迟为 0
-
执行命令查看从库状态:
show slave status\G
-
Seconds_Behind_Master: 0

两个值不等会出现什么情况
-
Retrieved_Gtid_Set > Executed_Gtid_SetIO 已经拉完日志,SQL 还没回放完 → 存在同步延迟。 -
正常同步完成:两个集合里主库发来的事务区间完全相等
#从库确认同步完成后,停止复制
stop slave;
reset slave all;#关闭只读模式,允许写入
SET GLOBAL read_only = OFF;
SET GLOBAL super_read_only = OFF;
#把原从库提升为主库set read_only=0;
#在原主库mysql5关闭只读锁
UNLOCK TABLES;#配置它去同步新主库
CHANGE MASTER TO
MASTER_HOST='新主库IP',
MASTER_PORT=3306,
MASTER_USER='repl',
MASTER_PASSWORD='repl123',
MASTER_AUTO_POSITION=1;START SLAVE;
如果希望下次重启后,mysql8服务器永久保持为主库:
-
把 node2 my.cnf 里的这一行删掉或者注释掉:
read_only = ON
-
保存后重启服务(实验切换时不需要做这一步,在线切换只改全局变量即可)。
MySQL5服务器全程不需要动 my.cnf,它本身已经是完整的 GTID 环境,做从库完全兼容。
3. 切换应用连接到新库
- 操作:修改项目数据库连接地址,把 IP 从旧主库改成原从库(新主库),重启业务服务。
- 此时原从库升级为新主库,接管所有读写业务。
4. 保留旧库作为回滚备份
- 旧主库暂时不删除、不清理数据,保持原样保留至少 7 天。
- 如果新库出现异常,可以立刻把业务切回旧主库,保障业务安全。
一致性校验
行数对比
SELECT table_name, table_rows FROM information_schema.tables
WHERE table_schema='db_itheima';
# 比如
SELECT table_name, table_rows FROM information_schema.tables where table_name like 'tb%';
哈希对比
SELECT MD5(GROUP_CONCAT(user_id ORDER BY user_id )) FROM tb_users;
校验字符集
SHOW VARIABLES LIKE 'character_set%';
校验权限对象是否迁移成功
SHOW PROCEDURE STATUS WHERE Db='db_itheima';
SHOW TRIGGERS FROM db_itheima;
SHOW EVENTS FROM db_itheima;
常见错误与解决方案
|----------------------------------------------|------------------|------------------------------------------|
| 问题 | 原因 | 解决方法 |
| 导入时报 "Invalid default value for 'timestamp'" | 8.0 的严格模式 | 在导入时加 --set-gtid-purged=OFF 并检查 sql_mode |
| 表结构不兼容 | 新旧版本 DDL 差异 | 手动调整表定义(尤其是 JSON、ENUM、索引前缀) |
| 性能慢 | 外键约束和 autocommit | 导入时关闭外键检查 |
| 数据不一致 | 中途中断或导入异常 | 再次导入该表或使用 pt-table-checksum 校验修复 |
主从数据一致性校验工具
Percona Toolkit
官网:https://www.percona.com/software/database-tools/percona-toolkit
#安装 Percona 仓库
dnf install https://repo.percona.com/yum/percona-release-latest.noarch.rpm -y
#启用对应仓库
percona-release enable tools release
#安装
dnf install percona-toolkit -y
#验证
pt-table-checksum --version
主从延迟怎么办
解决方案
-
优化网络配置:
- 增加网络带宽,减少主从之间的网络延迟。
-
提高硬件性能:
- 升级从库的硬件配置,例如使用SSD提高磁盘I/O。
-
减少从库负载:
- 使用多个从库实现读写分离如mycat读写分离操作,保证复制线程不受查询处理影响。
-
优化事务处理:
-
尽量减少主库大事务频率,将操作分解成多个小事务。
-
例如:如果需要插入大量记录,可将其拆分为多个较小的批量插入。
-
-
调优MySQL配置:
-
调整
innodb_flush_log_at_trx_commit等参数以提高写入效率,增加复制线程数量,如调整slave_parallel_workers。 -
innodb_flush_log_at_trx_commit参数调整- 默认值为
1,表示每次事务提交都会同步日志到磁盘。为了降低磁盘I/O,提高性能,可以设置为2,表示在事务提交时只写入日志缓存,定期刷入磁盘。
- 默认值为
-
增加复制线程数量 (
slave_parallel_workers)-
MySQL 5.7及以上版本支持并行复制。通过增加从库复制线程数可以加速从库应用事务。
-
在/etc/my.cnf中设置 slave_parallel_workers=4 # 根据服务器性能调整(最小为4,一般可以设置为CPU核心数的1/2或1/4),16核CPU => 4/8,32核CPU => 8/16
-
-