直接回答:把 sql 文件导入 MySQL 最常用的就两条命令——mysql -u 用户 -p 库名 < 文件.sql 或者进到交互界面后 source /路径/文件.sql。导入失败八成是三个原因:文件编码和连接字符集不一致、单条语句超过 max_allowed_packet、以及数据库里已经有同名表。

先看两种导入方式怎么选

方式 写法 适合场景
重定向 mysql -uroot -p db < backup.sql 大文件、脚本化、CI 里用
交互式 source 进 mysql 客户端后 source /path/backup.sql 临时导入、路径中含特殊字符不好处理时

两种本质一样,都是把 SQL 文本喂给客户端执行。source 的优点是可以先在客户端里 use 库名,并且出错时更容易看清是哪一行。

1
2
3
4
5
6
7
8
# 方式一:连接时直接指定库
mysql -h 127.0.0.1 -P 3306 -u devuser -p'密码' mydb < backup.sql

# 方式二:进客户端再 source
mysql -h 127.0.0.1 -u devuser -p
> CREATE DATABASE IF NOT EXISTS mydb DEFAULT CHARSET utf8mb4;
> USE mydb;
> source /home/me/backup.sql;

注意 -p 和密码之间不要有空格,-p 密码 会被当成两个参数。

导出:mysqldump 的常用姿势

导入之前通常先要导出:

1
2
3
4
5
6
7
8
9
10
11
# 只导结构
mysqldump -u root -p --no-data mydb > schema.sql

# 结构 + 数据,且写入前先删表(方便重复导入)
mysqldump -u root -p --add-drop-table mydb > full.sql

# 只导指定的几张表
mysqldump -u root -p mydb orders users > part.sql

# 一致性备份:不锁表,但保证导出数据一致
mysqldump -u root -p --single-transaction --master-data=2 mydb > full.sql

--single-transaction 对 InnoDB 很重要:它让导出期间不锁表、仍然一个一致性快照,线上库备份尽量加上,避免影响业务写入。

导入大文件要注意的参数

几十 MB 以上的文件,直接导经常在中间报错。提前做这几件事:

1
2
3
4
5
# 服务端:允许更大的单条语句
mysql -u root -p -e "SET GLOBAL max_allowed_packet = 268435456;"

# 导入时:指定字符集,避免中文变问号
mysql --default-character-set=utf8mb4 -u root -p mydb < full.sql

如果文件里有大量 INSERT,加上这两个参数能快不少(针对 InnoDB):

1
2
mysql -u root -p mydb < full.sql \
--init-command="SET autocommit=0; SET unique_checks=0; SET foreign_key_checks=0;"

代价是导入过程中不再做外键和唯一性检查,只在自己确认数据干净、且这段时间没人用它的时候用。

几个最常见的失败原因

1. 中文变成问号或乱码

导入和导出两端都要是 utf8mb4。老库里常见 utf8(其实是三字节的假 utf8),导到新库之前最好先把库和表统一改成 utf8mb4,否则 emoji 会直接报错。

2. ERROR 2006: MySQL server has gone away

基本就是单条语句超过了 max_allowed_packet。按上面的方法调大服务端和客户端两边的值,改完需要重连。

3. Table 'xxx' already exists

导入的库里已经有同名表了。要么在导出时带 --add-drop-table,要么导入前先删库重建:

1
2
DROP DATABASE IF EXISTS mydb;
CREATE DATABASE mydb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

4. 权限不足

导入需要 CREATE、INSERT 权限,带了建库语句还需要 CREATE DATABASE。用只读账号导入,报的错会让人以为文件有问题。

Docker 里导入的特别提醒

数据库跑在容器里时,mysql 客户端在容器内,你本地路径它看不见。两种做法:

1
2
3
4
5
6
# 方式一:把文件拷进容器再导
docker cp backup.sql mysqlserver:/tmp/backup.sql
docker exec -it mysqlserver sh -c 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" mydb < /tmp/backup.sql'

# 方式二:本地客户端连容器映射出来的端口(更推荐)
mysql -h 127.0.0.1 -P 3306 -u root -p mydb < backup.sql

方式二更简单:只要容器把 3306 映射出来,本地客户端连上去就行,文件根本不用进容器。但要注意大文件走网络可能比直接进容器慢,几 GB 的备份还是拷进容器更快。

导入完记得验证

导入成功不等于数据对。花一分钟确认一下:

1
2
3
4
USE mydb;
SHOW TABLES;
SELECT COUNT(*) FROM 关键表;
SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'mydb';

表数量对不上,往往是导出时漏了 --databases 或者漏了某张视图;行数对不上就去看导入日志里有没有被跳过的语句。


本文整理自我自己早先的操作笔记和一份入门资料,按"导出 → 导入 → 排查失败 → 验证"的顺序重新组织,并补充了 Docker 场景,文字由 AI 协助改写后经我复核。参数细节以所用 MySQL 版本的官方文档为准。

这篇笔记整理自我自己的实践记录,如果做法有出入,或者你踩过别的坑,欢迎到留言板一起聊聊。

站内搜索

没有找到内容!