hyperf批量插入必须用executemany+预处理语句,严禁拼接sql字符串;因手拼易致sql注入、乱码、字段错位及内存溢出,正确做法是用db::insert配合占位符与二维数组参数,并分批(≤500行)+手动事务控制。

Hyperf 里用 MySQL 客户端做批量插入,别直接拼 SQL 字符串,必须用 executemany + 预处理语句,否则极易触发 SQL 注入、乱码或字段错位。
为什么不能手拼 INSERT 多值字符串
很多人在 Hyperf 里写类似 "INSERT INTO user (name, age) VALUES ('张三', 25), ('李四', 30)" 这种字符串再 query 执行,看着快,实际埋雷:
- 中文或特殊字符(如单引号、反斜杠)未转义 → 报错或数据截断
- 用户输入进来的数据没过滤 → 直接被注入,
name可能是'张三'); DROP TABLE user; -- - 字段顺序一错,整批数据全插歪,比如把
age当成status插进去 - PHP 字符串拼接超长后内存溢出,尤其在协程里复用连接时容易崩溃
Hyperf 中正确使用 executemany
Hyperf 的 Db 组件底层基于 PDO,支持原生 executemany,这是唯一推荐的批量写法:
use Hyperf\Database\Connection;
$connection = $this->db->connection();
$sql = 'INSERT INTO users (name, age, email) VALUES (?, ?, ?)';
$data = [
['张三', 25, 'zhangsan@example.com'],
['李四', 30, 'lisi@example.com'],
['王五', 28, 'wangwu@example.com'],
];
$connection->insert($sql, $data); // 实际调用的就是 PDO::executemany
关键点:
-
$sql里只写一次占位符,不拼值;$data是二维数组,每行对应一行记录 - 所有类型自动绑定,
NULL写成null,DEFAULT需显式写'DEFAULT'并改用命名占位符或调整 SQL - 默认走事务,但不会自动
commit—— 如果你手动开启了事务,得自己commit或rollback
大批量导入时必须分批 + 控制事务粒度
哪怕用了 executemany,一次传 10 万行照样崩。MySQL 的 max_allowed_packet 默认才 4MB,按每行平均 200B 算,5000 行就超了:
- 单批建议 ≤ 500 行(比通用“1000 行”更保守,适配 Hyperf 协程高并发场景)
- 用
array_chunk($allData, 500)切分,循环执行insert - 不要把全部数据包在一个大事务里:每批单独事务,失败只回滚当前批,不影响后续
- 如果确定无主键冲突,可加
INSERT IGNORE前缀:INSERT IGNORE INTO users ...
LOAD DATA INFILE 在 Hyperf 里不是首选
虽然 LOAD DATA INFILE 速度最快,但它要求文件在 MySQL 服务端本地,且需 FILE 权限 —— 携程生产环境几乎禁用该权限,Hyperf 应用也无权访问数据库服务器磁盘:
- 本地开发调试可用,但上线前必须替换成
executemany路径 - 若真要走文件导入,得先用 SFTP 上传到 DB 机器,再由 DBA 手动执行,无法自动化
- Hyperf 自身不封装
LOAD DATA支持,硬写会破坏部署一致性
真正难的不是语法,是每批数据切多少、事务怎么收口、错误后怎么续传 —— 这些逻辑得写进业务层,不能依赖框架自动兜底。











