MySQL
FuelPHP
キャッシュ
ORM

FuelPHPのORMのメソッド利用時に、データ取得の結果が想定通りにならない時の対処法

More than 1 year has passed since last update.

fuelphpのORMが提供するメソッドを利用していてハマりました。

はまった内容としては

ORMのfindメソッドを利用して指定したidが一致するレコードを取得する際、検索結果をfuelがキャッシュし、次回以降同じidのレコード検索を行った時、SQLクエリが実行されず、キャッシュしたデータが返されるということ。

このせいでユニットテストが思うように動作してくれず、どハマりしました。


結論

fuelphpのORMにはデータのキャッシュ機能があるようで、テスト実行によるデータのキャッシュ履歴が、次のテストケースに影響を与えてしまっていました。


動作確認(ORMメソッド利用)

例えば次の処理を実行させます。

$user = Model_Users::find(1);

$user->name = 'name';
$user->save();
$user = Model_Users::find(1);

この処理を実行させた時にMySQLでは実際にどのようなクエリが実行されているかを確認してみます。

MySQLの実行クエリログを見る方法は

my.cnfのgeneral_logのフラグを1にしてやればOK

general_log_fileに指定されたファイルに実行クエリのログが吐き出されます。

では実際の結果を確認してみましょう。

Connect root@localhost on fuel_dev

Query SET NAMES 'utf8'
Query SELECT `t0`.`id` AS `t0_c0`, `t0`.`name` AS `t0_c1` FROM `users` AS `t0` WHERE `t0`.`id` = 1 LIMIT 1
Query UPDATE `users` SET `name` = 'hoge' WHERE `id` = '1'
Quit

ログを見てみると最後のfind文がクエリとして実行されていないことがわかります。


動作確認(クエリビルダ利用)

次にORMのメソッドではなく、クエリビルダを利用して実行してみます。

$user = Model_Users::find(1);

$user->name = 'name';
$user->save();
DB::select()->from('users')->where('id', '=', 1)->execute();

この場合のクエリ実行結果は以下の通りです。

Connect root@localhost on fuel_dev

Query SET NAMES 'utf8'
Query SELECT `t0`.`id` AS `t0_c0`, `t0`.`name` AS `t0_c1` FROM `users` AS `t0` WHERE `t0`.`id` = 1 LIMIT 1
Query UPDATE `users` SET `name` = 'hoge' WHERE `id` = '1'
Query SELECT * FROM `users` WHERE `id` = 1
Quit

クエリビルダを利用して実行すると、クエリがちゃんと実行されるようです。

よってクエリビルダを利用することで、キャッシュを使わず、DBにアクセスしデータを取得してくるようにできます。


まとめ

fuelphpのORMにはデータのキャッシュ機能があるので気を付けましょう。