讲解
业务系统经常要和外部交换数据:把订单导出给财务、把供应商的 CSV 导入商品库。MySQL 自带的文本导入导出一对组合是 SELECT ... INTO OUTFILE(查询结果写成文本文件)和 LOAD DATA INFILE(把文本文件高速装进表)。LOAD DATA 比逐条 INSERT 快几个数量级——它走的是批量解析通道,百万行 CSV 几十秒就能导完,是初始化数据和迁移数据的首选。
有一个安全限制必须先知道:secure_file_priv 参数限定了 OUTFILE/INFILE 能读写的目录,默认指向一个专用目录(本教程环境中是 /var/lib/mysql-files/),不允许写任意路径。INTO OUTFILE 还有个保护:目标文件已存在就报错,防止覆盖。FIELDS TERMINATED BY、ENCLOSED BY、LINES TERMINATED BY 三个子句描述文本格式,导出和导入两边必须写一致。
LOAD DATA 还有个 LOCAL 变体:LOAD DATA LOCAL INFILE 读的是客户端机器上的文件而不是服务器的。方便之余有安全风险——恶意服务器可以诱导客户端读取本地任意文件,所以客户端默认关闭 local_infile,用的时候才显式打开。另外 mysqldump --tab=目录 可以把每张表导出成「建表语句 .sql + 数据 .txt」的组合,本质是 OUTFILE 的封装。
示例
以练习库 learn 为例建表演示数据,确认安全目录后把数据导出为 CSV:
USE learn;
DROP TABLE IF EXISTS users;
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50),
city VARCHAR(20),
age INT
);
INSERT INTO users (name, city, age) VALUES ('李明', '北京', 25), ('王芳', '上海', 30), ('张伟', '广州', 28), ('刘洋', '深圳', 35);
SHOW VARIABLES LIKE 'secure_file_priv';
SELECT id, name, city, age
INTO OUTFILE '/var/lib/mysql-files/users_export.csv'
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM users;
用 LOAD DATA 把 CSV 高速导入一张同构新表,格式子句与导出时严格一致:
CREATE TABLE learn.users_imported LIKE learn.users;
LOAD DATA INFILE '/var/lib/mysql-files/users_export.csv'
INTO TABLE learn.users_imported
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\n';
SELECT * FROM learn.users_imported;
DROP TABLE learn.users_imported;
mysqldump --tab 把表导出为「建表语句 + 数据文本」两个文件(目录必须是 secure_file_priv 允许的):
# --tab 导出:users.sql 是建表语句,users.txt 是制表符分隔的数据
mysqldump -uroot -p --tab=/var/lib/mysql-files learn users
ls -l /var/lib/mysql-files/users.sql /var/lib/mysql-files/users.txt
rm -f /var/lib/mysql-files/users.sql /var/lib/mysql-files/users.txt /var/lib/mysql-files/users_export.csv
常见坑
- OUTFILE 路径被拒:报 1290 错误多半是没写在 secure_file_priv 允许的目录里。先 SHOW VARIABLES 查清楚,这个参数只能改配置重启。
- 导入导出格式子句不一致:导出用逗号分隔、导入按制表符读,数据全部挤进第一列或报错 1261/1262。两边的 FIELDS/LINES 子句逐字符对齐。
- CSV 中文乱码:文件编码与连接的字符集不一致,LOAD 进去变成乱码。LOAD DATA 时可用 CHARACTER SET utf8mb4 子句声明文件编码。
- 随意开启 LOCAL INFILE:恶意服务器可利用它读取客户端本地文件(如 SSH 私钥)。确实需要才开,用完关掉,这是业界通报过的真实攻击手法。
小结
SELECT INTO OUTFILE 导出、LOAD DATA INFILE 高速导入,格式子句两边一致,secure_file_priv 限制目录;LOCAL 变体有安全风险,mysqldump --tab 是封装好的导出。下一章回到库内对象:视图。