java中无法直接通过preparedstatement执行load data infile,必须用statement并启用allowloadlocalinfile=true连接参数,且服务端需开启local_infile、用户需有file权限;文件路径须为客户端绝对路径,编码需匹配utf-8,推荐配合事务控制与索引禁用提升千万级导入性能。

Java 中无法直接通过 JDBC 的 PreparedStatement 执行 LOAD DATA INFILE,因为该语句属于 MySQL 服务端特有语法,且 JDBC 驱动默认禁用(出于安全考虑)。但可通过绕过 JDBC 标准执行路径、启用特定连接参数并调用 MySQL 原生命令的方式实现——核心在于:**让 MySQL 服务端直接读取服务端本地文件,或使用 `LOCAL INFILE` 模式读取客户端文件,并在 JDBC 连接中显式授权**。
前提条件:MySQL 服务端配置与权限开通
这是最关键的一步,缺一不可:
-
服务端需开启
local_infile:在 MySQL 配置文件(my.cnf或my.ini)的[mysqld]和[client]段均添加local_infile=ON,然后重启 MySQL; -
JDBC 连接必须显式启用
allowLoadLocalInfile=true,例如:jdbc:mysql://localhost:3306/db?useSSL=false&allowLoadLocalInfile=true; -
对应数据库用户需拥有
FILE权限(注意不是普通 DML 权限),执行:GRANT FILE ON *.* TO 'your_user'@'%'; FLUSH PRIVILEGES;; - 若使用
LOAD DATA INFILE(无 LOCAL),文件必须位于 MySQL 服务端机器上,且 MySQL 进程有读取权限;
若使用LOAD DATA LOCAL INFILE,文件在 Java 应用所在机器(客户端),更常用也更灵活。
Java 中执行 LOAD DATA LOCAL INFILE 的正确写法
不能用 PreparedStatement,必须用 Statement,且 SQL 字符串需完整拼写(字段名、分隔符、忽略首行等按需设置):
String sql = "LOAD DATA LOCAL INFILE '/path/to/data.csv' "
+ "INTO TABLE user_info "
+ "FIELDS TERMINATED BY ',' "
+ "OPTIONALLY ENCLOSED BY '"' "
+ "LINES TERMINATED BY '\n' "
+ "IGNORE 1 ROWS "
+ "(id, name, email, created_time)";
try (Statement stmt = connection.createStatement()) {
int affected = stmt.executeUpdate(sql); // 返回实际导入行数
System.out.println("导入完成,影响 " + affected + " 行");
}
⚠️ 注意:路径必须是 Java 进程可访问的绝对路径(Windows 用双反斜杠或正斜杠均可,如 C:/data/user.csv);CSV 文件编码需与数据库表字符集一致(建议 UTF-8 并在连接参数中指定 characterEncoding=utf8)。
千万级数据入库的实用优化技巧
-
关闭自动提交 + 手动事务控制:虽然
LOAD DATA本身是原子操作,但若需与其他操作一起事务化,可在执行前connection.setAutoCommit(false),成功后commit(); -
预处理 CSV 文件:确保无非法换行、多余引号、NULL 值格式统一(如用
N表示 NULL,配合SET col_name = NULLIF(@col_name, '\N')); -
临时禁用索引和外键(仅限离线导入场景):
ALTER TABLE user_info DISABLE KEYS;→ 执行 LOAD →ALTER TABLE user_info ENABLE KEYS;;
外键检查可临时关闭:SET FOREIGN_KEY_CHECKS = 0;; -
分批次拆分大文件:单个超大 CSV(如 5GB)易触发内存或超时,建议按 500 万行/文件切分,Java 中循环调用
LOAD DATA LOCAL INFILE; -
JDBC 连接参数追加优化项:
rewriteBatchedStatements=true&useServerPrepStmts=false&cachePrepStmts=true对此场景作用有限,但socketTimeout=0(禁用超时)可避免大文件传输中断。
替代方案对比:什么时候不该用 LOAD DATA?
如果无法满足上述安全配置(如云数据库 RDS 默认禁用 local_infile,且不开放 FILE 权限),则应转向其他高性能批量方式:
-
MyBatis Batch Insert:配合
ExecutorType.BATCH+addBatch()/executeBatch(),每 1 万条 commit 一次; -
JDBC Batch + rewriteBatchedStatements:开启 MySQL 驱动批处理重写,将多条 INSERT 合并为
INSERT INTO ... VALUES (),(),(); - 使用 DataX / SeaTunnel 等专用同步工具:适合跨异构源、调度稳定、监控完善的生产环境。
不复杂但容易忽略。关键不在 Java 写法多巧妙,而在于 MySQL 侧是否真正放行、文件路径是否可达、数据格式是否干净。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











