如何通过PDO将db.sql导入MariaDB?替代mysqli_multi_query函数
嘿,刚好我对这个问题挺熟悉的!首先明确一点:PDO并没有和mysqli_multi_query()完全等价的内置函数,但咱们有好几种靠谱的办法实现批量导入SQL到MariaDB的效果,下面给你详细拆解每种方案的用法和适用场景:
使用PDO批量导入SQL文件到MariaDB的方法
方法1:开启多语句支持后用exec()执行
默认情况下PDO的exec()只能跑单条SQL,但如果在创建连接时开启PDO::MYSQL_ATTR_MULTI_STATEMENTS属性,就能一次性执行所有用分号分隔的语句,和mysqli_multi_query()的逻辑最接近。
示例代码:
// 先读取SQL文件内容 $sqlContent = file_get_contents('db.sql'); // 创建PDO连接时开启多语句支持 $dsn = 'mysql:host=localhost;dbname=你的数据库名;charset=utf8mb4'; $username = '你的用户名'; $password = '你的密码'; $options = [ PDO::MYSQL_ATTR_MULTI_STATEMENTS => true, // 这是关键配置 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION // 开异常模式方便调试错误 ]; try { $pdo = new PDO($dsn, $username, $password, $options); // 一次性执行所有SQL $affectedRows = $pdo->exec($sqlContent); echo "导入成功,总共影响了 $affectedRows 行数据"; } catch(PDOException $e) { die("导入炸锅了:" . $e->getMessage()); }
小提醒:这个方法虽然简单,但有个坑——如果你的SQL里有字符串包含未转义的分号(比如
INSERT INTO posts(content) VALUES('Hi; 这是带分号的内容')),PDO会把它当成语句分隔符,导致解析错误。所以只适合结构规范、没有特殊字符的SQL文件。
方法2:手动拆分SQL语句逐条执行(更安全)
想要避免分号的坑,最稳妥的方式是手动拆分SQL语句,跳过字符串内部的分号,然后逐条执行。这种方法兼容性拉满,适合复杂的SQL文件。
示例代码:
$sqlContent = file_get_contents('db.sql'); // 先预处理SQL:去掉注释和空行 $sqlContent = preg_replace('/^\s*--.*$/m', '', $sqlContent); // 清除单行注释 $sqlContent = preg_replace('/\/\*.*?\*\//s', '', $sqlContent); // 清除多行注释 $sqlContent = preg_replace('/^\s*$/m', '', $sqlContent); // 清除空行 // 创建PDO连接 $dsn = 'mysql:host=localhost;dbname=你的数据库名;charset=utf8mb4'; $username = '你的用户名'; $password = '你的密码'; $pdo = new PDO($dsn, $username, $password, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]); // 智能拆分SQL语句(跳过字符串里的分号) $statements = []; $currentStmt = ''; $inString = false; $quoteChar = ''; for ($i = 0; $i < strlen($sqlContent); $i++) { $char = $sqlContent[$i]; // 处理字符串边界(单引号/双引号) if (($char === "'" || $char === '"') && (!$inString || $quoteChar === $char)) { $inString = !$inString; $quoteChar = $inString ? $char : ''; } // 不在字符串里时,遇到分号就拆分语句 if (!$inString && $char === ';') { $stmt = trim($currentStmt); if (!empty($stmt)) { $statements[] = $stmt; } $currentStmt = ''; } else { $currentStmt .= $char; } } // 处理最后一条没带分号的语句 $finalStmt = trim($currentStmt); if (!empty($finalStmt)) { $statements[] = $finalStmt; } // 开启事务批量执行,出错可以回滚 try { $pdo->beginTransaction(); foreach ($statements as $stmt) { $pdo->exec($stmt); } $pdo->commit(); echo "所有SQL都执行成功啦!"; } catch(PDOException $e) { $pdo->rollBack(); die("执行失败:" . $e->getMessage()); }
方法3:调用系统命令(适合超大文件)
如果你的SQL文件特别大(比如几百MB),用PHP处理效率可能不高,直接调用系统的mysql命令行工具会更快:
$dbName = '你的数据库名'; $username = '你的用户名'; $password = '你的密码'; $sqlFile = 'db.sql'; // 构建命令(怕密码泄露的话,可以用--defaults-extra-file指定配置文件) $command = "mysql -u $username -p$password $dbName < $sqlFile"; // 执行命令 exec($command, $output, $returnVar); if ($returnVar === 0) { echo "超大文件导入成功!"; } else { echo "导入失败,错误信息:" . implode("\n", $output); }
注意:这种方法需要PHP环境允许执行系统命令,并且要做好密码的安全防护,别把明文密码暴露在命令行里。
内容的提问来源于stack exchange,提问作者Andrea
相关产品推荐
相关产品推荐

