目前,SQLite3 PHP 绑定(不是 SQLite3 本身)存在一个问题,导致所有查询都被执行两次。它显然已经存在一段时间了。
有关更多信息,请参见此处:https://bugs.php.net/bug.php?id=64531
在发现上述问题之前,我发布了以下内容:http://stackoverflow.com/questions/36617708/odd-behavior-with-sqlite3-non-select-prepared-transactions-and-fetcharray(包括复制粘贴的错误演示)
解决方法:我强烈建议将可能在非 SELECT 查询结果上运行 fetchArray() 的任何代码包装在 numColumns() 检查中,如下所示
<?php
$op = $db->prepare(...);
$r = $op->execute(); // 查询 #1
if ($r->numColumns()) { // 返回列数,这里用作真/假测试
while ($row = $r->fetchArray(SQLITE3_ASSOC)) { // 查询 #2
// 您的代码在此处
}
}
?>
澄清
- 查询 #1 是 SQLite3 查询第一次执行的地方,查询 #2 是查询再次执行的地方。是的,*所有内容* 都被执行了两次;这就是错误。
- 如果您的代码只从数据库中读取而不会更改数据库(例如,不会导致数据库更改触发的 SELECT),那么您就没事。您的查询运行两次,但它不会更改结果。
- 如果您的代码要写入数据库 - 例如 INSERT - 那么如果列数为零,则*必须*不要运行 fetchArray()(并再次执行查询)。
- 它在手册中没有记录,但在这里 -https://php.net/manual/en/book.sqlite3.php#113144 - 用户 'bohwaz' 提到从 PHP 5.3.11 开始,还有一个 SQLite3Stmt::readOnly() 函数可以告诉您是否刚刚写入数据库。这目前没有记录,但可能是 numColumns() 的更合适的替代方案(我不确定它做了什么,它可能与 numColumns() 相同)。
您可能更喜欢使用 PDO 来进行更高容量的 SQLite3 工作。讽刺的是,这个绑定更轻量级,并提供对一些特定于 SQLite3 的原语和行为的直接访问... 但它运行所有查询两次。
[[注意主持人(此部分可以在阅读后删除;我对以下内容也持开放态度)
- 请不要将此评论视为错误报告 - 我只是希望其他人知道这个问题,这样他们就不会花几个小时挠头了。:P
- 截至提交此评论的日期,此页面有一个未经批准的 diff 停留在 DocBook 中,因此我无法添加类似 "由于错误 #64531,建议您将 fetchArray() 包装在 numColumns() 中..." 的内容,我认为这将比此评论更有说服力,直到这个错误得到修复。]]]