mtmr_t's blog

ひよっこiosぷろぐらま

symfony の fetch()つかってたらエラー。fetchAllってなんぞ?

今回symfonyを使っての開発でまたエラー的な何かが。
解決したのは先輩なんだけど、一応残しておく+ちゃんと知っとこうと思って調べてみました。

出ていたエラーはコチラ

" General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll()"とかなんとかかんとか

とりあえずPDOまわりのことでしかもfetchAllについてらしいが、よくわからない。
このときはソース内では普通にfetch()を使っていて、
しかもローカルでも検証用環境動作していたため、運用用の環境で突然起きたことがイミフ状態。

自分達のやっている開発では、結局解決策はfetch()を使っている箇所をすべてfetchAll()にするという方法でした。
が、いまいちなんで使っちゃいけないのか私全然わかってない・・よ!
とりあえず直したら動くよみたいな!


というわけで、ちょっとググッてみた以下
http://rugoh.dgblog.dreamgate.gr.jp/e64160.html

PDOに関連するらしい。自分のSymfony+PHPだけではなくてOpenPNEとかの開発でも同じ現象おきるんですね。

まぁまずはfetch()って何ぞ?
http://php.net/manual/ja/pdostatement.fetch.php
switchでくるくる回しながら1レコード配列づつ取得しつつ、
$使いたい変数 = $row['カラム名'];
みたいな感じで使うものというイメージ。

そして話題のfetchAll()って何さ?
http://php.net/manual/ja/pdostatement.fetchall.php
すべてのレコード内容を一気に取得するので、
$row[i番目のレコード]['カラム名']みたいに使うイメージ。

ループで回してあげればいいってことかな。
とりあえずこの方法で自分達は回避したのですが・・・

でも何でfetch()ではなくてfetchAll()使わないとなの!?
書き直しが全然難しくはないけど最後に知ったらめんどいじゃない!?
使用条件とかあるんじゃないの?!

荒らぶりましたがさらに調べてみることに。

http://docwiki.embarcadero.com/VCL/ja/DBTables.TBDEDataSet.FetchAll

重要そうなのはこのあたり?
利点)
キャッシュアップデートを使用するときのネットワークトラフィックを減らすことができます。
欠点)
同時に多数のクライアントによって使用されているデータベースにアクセスし,同一のレコードの更新の競合が頻繁に起こる場合,一度にすべてのレコードを取り出すことは必ずしも有効ではありません。
といったところでしょうか。

他にも互換性があるのかな?
http://manual.xwd.jp/ref.pdo-mysql.html
PDOStatement でこの属性を TRUE に設定すると、 MySQL ドライバはバッファ版の MySQL API を使用します。 移植性の高いコードを書くには、代わりに PDOStatement::fetchAll() を使用すべきです。

DBアクセス時のスタイルが変わるってことかな?
でも他のDBに移植しやすいfetchAll使ったほうがいいよって書いてありますね。


このようにfetchAllの利点欠点がなんとなく判ったので、じゃあなぜ自分達の環境ではfetch()を認めてくれないエラーがでていたのか?

そういえば先輩が言っていたことを思い出しました。
「fetch()のループの中でfetch()したらエラーでるよ」と。
これのことかああああ!
http://www.infinity-blue.jp/archives/48

うん、なんとなくつながったかも。

つまり…

fetch()は2回重複できません、
重複するfetch()使うなら、PDO::MYSQL_ATTR_USE_BUFFERED_QUERYの値をtrueにするように。
ただしこの設定はmySQLのみのもので、互換性がないため、
互換性のあるfetchAll()を利用したほうが良い。

また、開発中の案件内容によってはfetchAll()を使うことで
同一のレコードの更新の競合が頻繁に起こる場合がありうるのであれば、
使用箇所の検討や方針が必要になり、fetch()を使ったほうがよい場合も存在する。

こんなところですかね。
今回の疑問は大体とけたのでここまで。

ここちがうよ!とか
こうしたほうがいいよ!というやり方があれば
突っ込んでやってください。