Musíte načítat, dokud se nezdaří pokus o načtení řádku. Vím, že můžete mít ve výsledné sadě pouze jeden řádek a myslíte si, že jedno načtení stačí, ale není tomu tak (když používáte dotazy bez vyrovnávací paměti). PDO neví, kolik řádků je, dokud nedosáhne konce, kde se pokusí načíst další řádek, ale selže.
Pravděpodobně máte jiné výroky, kde jste plně "aportovali, dokud se aport nezdařil". Ano, vidím, že načítáte, dokud jeden načítání selhalo prohlášení, ale to neznamená, že jste to udělali pro všechny.
Abychom objasnili -Když spustíte dotaz pomocí execute(), vytvoříte sadu výsledků, která musí být načtena z db do php. PDO může zpracovat pouze 1 z těchto "souboru výsledků, které se načítají" najednou (na připojení). Než budete moci začít načítat jinou sadu výsledků z jiného volání funkce execute(), musíte kompletně načíst sadu výsledků, celou cestu až na její konec.
Když "voláte fetch(), dokud se fetch() nezdaří", PDO interně zaznamená skutečnost, že jste dosáhli konce výsledků, když poslední volání fetch() selže, protože již neexistují žádné další výsledky. PDO se pak přesvědčí, že výsledky jsou plně načteny, a může vyčistit jakékoli interní zdroje mezi php a db, které byly vytvořeny pro danou sadu výsledků, což vám umožní vytvářet/načítat další dotazy.
Existují i jiné způsoby, jak udělat PDO "volat fetch(), dokud fetch() selže".
- Stačí použít fetchAll(), která jednoduše načte všechny řádky, takže se dostane na konec sady výsledků.
- nebo stačí zavolat closeCursor()
*Pokud se podíváte na zdroj closeCursor(), výchozí implementace doslova načte řádky a zahodí je, dokud nedosáhne konce. Je to samozřejmě napsané v c, ale víceméně to dělá toto:
function closeCursor() {
while ($row = $stmt->fetch()) {}
$this->stmtFullyFetched = true;
}
Některé ovladače db mohou mít efektivnější implementaci, která od nich nevyžaduje načítání spousty řádků, o které se nikdo nestará, ale to je výchozí způsob, jak to PDO dělá. Každopádně...
Při použití dotazů s vyrovnávací pamětí obvykle tyto problémy nemáte. Důvodem je to, že u dotazů s vyrovnávací pamětí, hned poté, co je provedete, PDO automaticky plně načte výsledky db do paměti php, takže za vás automaticky provede část „volání fetch() dokud se nezdaří fetch()“. Když později sami zavoláte fetch() nebo fetchAll(), bude to načítat výsledky z paměti php, nikoli z db. Takže v zásadě je výsledná sada okamžitě plně načtena při použití dotazů s vyrovnávací pamětí, takže není příležitost mít více než 1 „probíhající načítání sady výsledků“ (protože php je jednovláknové, takže není šance na 2 dotazy běží ve stejnou dobu).
Vzhledem k tomu:
$sql = "select * from test.a limit 1";
$stmt = $dbh->prepare($sql);
$stmt->execute(array());
Způsoby, jak plně načíst sadu výsledků (za předpokladu, že chcete pouze první řádek):
$row = $stmt->fetch();
$stmt->closeCursor();
nebo
list($row) = $stmt->fetchAll(); //tricky
nebo
$row = $stmt->fetch();
while ($stmt->fetch()) {}