仅执行CREATE TABLE时mysqli::multi_query对mysqli_stmt::prepare的影响
问题1解答
使用mysqli::query执行查询时,无论是否是默认的MYSQLI_STORE_RESULT模式,单条查询执行完成后mysqli底层会自动清空结果缓冲区,不需要主动获取记录就可以执行后续查询。
需要注意的是mysqli::query本身默认不支持执行多语句,执行多查询只能调用multi_query方法,二者的底层处理逻辑完全不同。
问题2解答
底层运行逻辑
这是MySQL客户端/服务端通信协议的强制要求:只要调用multi_query发送了多条SQL,服务端会按顺序返回所有SQL的执行应答包,哪怕是建表这类没有结果集的DDL语句,也会返回执行成功/失败的状态应答,这些应答都会暂存到MySQL连接的缓冲区中,必须全部读取处理完成,连接才会回到空闲状态,才能发起新的查询请求。
单条query执行完成后,mysqli会自动读取唯一的应答包清空缓冲,所以后续调用prepare不会有问题。但multi_query仅会返回第一条SQL的执行状态,剩余所有SQL的应答都还留在缓冲区中未被处理,此时连接处于占用状态,调用prepare会直接失败返回false,就是你遇到的报错原因。
清空缓冲区的方法
哪怕没有返回结果集,也可以通过循环读取所有待处理结果的方式清空缓冲区,在multi_query执行后添加以下代码即可:
if ($result) { // 清空缓冲区逻辑 do { if ($res = $conn->store_result()) { $res->free(); } } while ($conn->more_results() && $conn->next_result()); // 后续执行prepare操作就不会报错 $stmt = $conn->prepare("INSERT INTO `admins` (username, password) VALUES (?, ?)"); $stmt->bind_param("ss", $admin_name, $admin_pass1); $stmt->execute(); }
这段代码会遍历读取所有待处理的应答,遇到结果集就释放,没有结果集也会把状态应答读取完清空缓冲区,处理完成后连接就能正常执行新的查询了。
内容的提问来源于stack exchange,提问作者user31782
相关产品推荐
相关产品推荐

