Issei.M's Techlog

Web/iOS エンジニアの僕が技術関連のメモ等をつらつらと。主に Symfony について書いています。

[Doctrine] SQLiteでQuery::iterate()を使うとDBがロックする件

僕はSymfony+Doctrineプロジェクトで機能テストを作る際、 LiipFunctionalTestBundle を使ってテスト環境だけSQLiteで動作するようにしているのですが、ある時から途中でDBがロックしてしまい、テストスイートがパスしなくなってしまいました。

SQLSTATE[HY000]: General error: 5 database table is locked

原因を探っていくうちに、以下のテストケースに問題がある事が分かりました。

<?php

$query = $entityRepository->createHogeQuery(); // Doctrine\ORM\Query

$iterator = $query->iterate();
$iterator->rewind();

$this->assertSame($expectedEntity, $iterator->current()[0]);

実際にアプリケーションでも大量の結果セットを返す可能性のある::createHogeQuery()iterate()して使っていたのでテストも同様にしたのですが、横着したのがいけなかったようです。

どう言う事かと言うと、iterate()を使う場合は最後の行までフェッチしないと、内部のPDOStatementcloseCursor()されないようで、その結果次回以降のテストに影響が出ていたと言うわけです。

テストに以下を追加する事でとりあえず解決しました。

<?php

while ($iterator->next()); // cleanup

あるいは、テストデータの量はたかがしてれているのでそもそもテストではiterate()を使わなければ良いのかもしれません。
ところでこれ、普通にforeachしたとしてもbreakされたら同様の事が起きそうですよね。誰か試してみて下さい。