(PHP)PDO使用時はPDOStatementをした方がよい
PDOを使って、選択クエリ発効後、挿入クエリをするスクリプトを書いています。
選択クエリは、fetch メソッドで先頭行のみ取得しており、挿入クエリでは、トランザクションを使っています。
しかし、挿入クエリの、beginTransaction() で下記のようなエラーが。。。
Fatal error: Maximum execution time of 30 seconds exceeded in D:\eclipe\testl\util.php on line 100
原因として選択クエリ後に、PDOStatement を解放してなかったのがまずいようです。
PHPリファレンス:PDO::queryには、「PDO::query() を次にコールする前に 結果セット内の全てのデータを取得しない場合、そのコールは失敗します。 PDOStatement::closeCursor() をコールし、 次に PDO::query() をコールする前に PDOStatement オブジェクトに関連付けられたリソースを解放してください。」とあります。
fetch 後、PDOStatement::closeCursor() を実行することで、ちゃんと動くようになりました。
下記のような感じです。(ADD関数は、DB追加時に汎用性を持たすようにしたものです。詳しくは、(PHP)PDOでforeachを使ってbindParamでパラメータを設定してた時の注意点を参照。)
$employeeCode = '015640';
$departmentCode = '201';
try {
// DBに接続する
$db = new PDO( 'sqlite2:./test.sqlite', '', '' );
//件名カテゴリ取得
$stmt = $db->prepare( 'SELECT * FROM employee WHERE employee_code = :code' );
$res = $stmt->execute(array(':code' => $employeeCode ) );
$res = $stmt->fetch(PDO::FETCH_BOTH);
$employeeId = $subject . $res['id'];
//↓これが必要。これで他の SQL ステートメントを発行できるようにサーバへの接続を解放。
$stmt->closeCursor();
//件名カテゴリ取得
$stmt = $db->prepare( 'SELECT * FROM department WHERE department_code= :code' );
$res = $stmt->execute(array(':code' => $departmentCode ) );
$res = $stmt->fetch(PDO::FETCH_BOTH);
$departmentId = $subject . $res['id'];
//↓これが必要。これで他の SQL ステートメントを発行できるようにサーバへの接続を解放。
$stmt->closeCursor();
//DBにデータ追加
Add('project', array('employee_id','department_id'),array($employeeId , $departmentId) );
// DBから切断する ( $db = null; も可能)
unset( $db );
} catch (PDOException $e) {
// DBアクセスができなかったとき
'アクセスできません : ' . $ex->getMessage();
unset( $db );
die();
}
/* DBにデータを追加するSQL文
* $tbl:テーブル名
* $clm_ary:列名の配列
* $value_ary:値の配列($clm_aryの要素Noにあったデータを入れること)
*/
function Add($tbl,$clm_ary,$value_ary){
try {
//sql文組立て
$sql_part1 = '';
for ($i = 0; $i < count($clm_ary); $i++) {
$sql_part1 = $sql_part1 . ' ? ';
if( $i < count($clm_ary)-1) {
$sql_part1 = $sql_part1 . ",";
}
}
$sql_part2 ='';
for ($i = 0; $i < count($value_ary); $i++) {
$sql_part2 = $sql_part2 . ' ? ';
if( $i < count($value_ary)-1) {
$sql_part2 = $sql_part2 . ",";
}
}
$sql = 'INSERT INTO ?( ' . $sql_part1 . ') VALUES (' . $sql_part2 . ')';
// DBに接続する
$db = new PDO( 'sqlite2:./test.sqlite', '', '' );
//SQL警告出すようにする
$db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
//トランザクション開始。 closeCursor 無いとここでエラー。
$stmt=$db->beginTransaction();
$stmt = $db->prepare( $sql );
//パラメータ指定
$i = 1;
$stmt->bindParam($i, $tbl);
foreach($clm_ary as $key => &$clm) {
$i++;
$stmt->bindParam($i, $clm);
}
unset($clm);
foreach($value_ary as $key => &$value) {
$i++;
$stmt->bindParam($i, $value);
}
//クエリ実行
$res = $stmt->execute();
//コミット
$stmt= $db->commit();
$db=null;
}catch( PDOException $ex ) {
// DBアクセスができなかったとき
print 'DBにデータ追加失敗。 : ' . $ex->getMessage();
unset( $db );
die();
}
}
参考: