ThinkPHP 7 不支持直接执行含多语句的 SQL 文件,需手动读取文件、按分号拆分、过滤注释与空行后,在事务中逐条执行;DDL 语句可能触发隐式提交,SET/USE 等会话命令需提前过滤。

ThinkPHP 7 本身不直接支持“执行整个 SQL 文件并自动包裹事务”,但你可以通过手动控制事务 + 分段执行 SQL 语句的方式,实现带事务保障的 SQL 文件导入。
SQL 文件执行本质是多条语句拼接
TP7 的 Db::execute() 或 Db::statement() 只能执行单条 SQL 语句(如 INSERT、UPDATE、CREATE TABLE),不支持分号分隔的多语句批量执行(PHP PDO 默认禁用 multi_query,出于安全考虑)。因此,像包含建表、插入、更新等多条语句的 .sql 文件,不能直接传给 TP7 执行。
常见做法是:先用 PHP 读取文件 → 按分号拆分成独立语句 → 过滤空行和注释 → 逐条调用 Db::execute()。这个过程必须由你显式开启和提交事务。
手动事务控制是唯一可靠方式
要在执行 SQL 文件时保证原子性(全成功或全回滚),需在语句循环外开启事务:
立即学习“PHP免费学习笔记(深入)”;
- 调用 Db::startTrans() 开启事务
- 遍历每条有效 SQL,用 Db::execute($sql) 执行
- 任一语句失败(抛出异常或返回 false),立即调用 Db::rollback()
- 全部成功后调用 Db::commit()
注意 SQL 文件内容的兼容性
并非所有 SQL 都能在 TP7 中安全执行:
-
DDL 语句(如 CREATE、ALTER、DROP) 在部分 MySQL 配置下可能触发隐式提交,导致事务失效;建议确认 MySQL 的
autocommit=0且不涉及临时表、存储过程创建等敏感操作 - SET、USE、DELIMITER 等会话级命令 不被 PDO execute 支持,需提前过滤或跳过
- 含反引号或特殊字符的语句 要确保 PHP 解析时不破坏语法,推荐使用 file_get_contents + preg_split('/;\s*$/m', ...) 并严格 trim
推荐轻量封装示例
可写一个工具方法,接受 SQL 文件路径,内部完成读取、拆分、事务执行:
```php
public function importSqlFile(string $filePath): bool
{
if (!is_file($filePath)) {
throw new Exception("SQL file not found: {$filePath}");
}
$sqlContent = file_get_contents($filePath);
$statements = array_filter(array_map('trim', preg_split('/;\s*$/m', $sqlContent)));
Db::startTrans();
try {
foreach ($statements as $sql) {
if (empty($sql) || str_starts_with($sql, '--') || str_starts_with($sql, '#')) {
continue;
}
Db::execute($sql);
}
Db::commit();
return true;
} catch (Throwable $e) {
Db::rollback();
throw $e;
}
}



















