次のような MySQL クエリを生成する PHP スクリプトがあります。
INSERT INTO `dailydb`.`probact_actionstaken`(`dispatcher`) VALUES ('kryan');
SET @actionTakenId = LAST_INSERT_ID();
INSERT INTO `dailydb`.`probact_actionstaken_types`(`actionTaken`,`type`)
VALUES
(@actionTakenId, 2);
INSERT INTO `dailydb`.`probact_actionstaken_problems`(`actionTaken`,`problem`)
VALUES
(@actionTakenId, 2);
INSERT INTO `dailydb`.`probact_actionstaken_actions`(`actionTaken`,`action`)
VALUES
(@actionTakenId, 3);
INSERT INTO `dailydb`.`probact_actionstaken_text`(`actionTaken`,`input`,`value`)
VALUES
(@actionTakenId, 3, '7576'),
(@actionTakenId, 4, 'B61'),
(@actionTakenId, 5, '4'),
(@actionTakenId, 6, 'kryan'),
(@actionTakenId, 7, 'test'),
(@actionTakenId, 8, 'testing new debug');
SELECT `index`, `timestamp`
FROM `dailydb`.`probact_actionstaken`
WHERE `index`=@actionTakenId;
(このクエリを表示する目的で、:someId
準備済みステートメントを使用しているため、すべての値は手動で検索して対応する値に置き換えた結果であることに注意してください)
( probact_actionstaken
.index
は自動インクリメントの主キーであり、probact_actionstaken
. のtimestamp
デフォルトはCURRENT_TIMESTAMP
)
クエリの目的は、( に格納されているprobact_actionstaken
.の自動値に基づいて) 大量の関連データを挿入し、自動生成されて使用できるようにすることです (スクリプトは、この出力を使用する AJAX 呼び出しで呼び出されます)。 )。index
@actionTakenId
index
timestamp
このクエリは、ほとんどの部分で正しく実行されます。5 つのINSERT
ステートメントはすべて、データベースに正しい値を挿入します。私の問題はその最後のSELECT
声明です。次の PHP コードを使用して、クエリの結果を調べてみました。
$statement = $dbh->prepare($query);
$statement->execute($params);
$output['results'] = array();
do
{
$output['results'][] = array();
while ( $result = $statement->fetch(PDO::FETCH_ASSOC) )
{
$output['results'][count($output['results'])-1][] = $result;
if ( isset($result['index']) )
{
$output['index'] = intval($result['index']);
}
if ( isset($result['timestamp']) )
{
$output['timestamp'] = $result['timestamp'];
}
}
} while ( $statement->nextRowset() );
echo json_encode($output);
アイデアは、do...while
ブロックを使用してINSERT
ステートメントからの結果を取得し、その最終SELECT
ステートメントの結果を取得して my に格納すること$output
です。
私のローカル マシン (PHP 5.4.4 を実行) では、これは完全に機能します。PHP 5.3.10 を搭載したサーバーでは$statement->nextRowset()
毎回 false が返されるため、最初の行セットのみを取得します (これはINSERT
ステートメントからのものであるため空です)。実際の挿入は関係なく正しく機能することに注意してください。手動で入力した上記のクエリを phpMyAdmin の SQL 機能で実行すると、正しい結果 (挿入されたインデックスとタイムスタンプで構成されるテーブル) が返されます。
これらの問題について読むと、このような複数のステートメントは悪い考えであり、実際には真の準備済みステートメントでは機能しないようです。私はまだデフォルトのエミュレートされた準備済みステートメントを使用しています。$dbh->prepare
そのため、との個別の呼び出しに切り替えることができました$statement->execute
。これで問題は解決しますが、競合状態が心配です。サーバーは Nginx を使用しており、多くのユーザーが同時にエントリを入力する可能性があります。LAST_INSERT_ID()
他のユーザーのエントリを返して、これらのフィールドを間違ったアクションに関連付けたくありません。
競合状態の問題を防ぐために、MySQL または PHP 内に何らかの理由がありますか? 私が取ることができるいくつかのステップ?または、複数の準備済みステートメントを使用する安全な方法はありますか? 後者の場合、PHP 3.5.10 で動作しますか?