3

PDOを使用して、DROP TABLEIFEXISTSで始まるストアドプロシージャを呼び出しています。PDOException'SQLSTATE [42S02]がランダムに発生します:ベーステーブルまたはビューが見つかりません:1146テーブル' historygr.reached'が存在しません'そしてさらに厄介なことに、それを通知することから、テーブルは、同じ接続からのように見えますが、互いに数秒以内にすでに存在しています。

自分でエラーをトリガーすることはできませんが、エラー通知を受け取ります。

エラーの原因となったPHPは次のとおりです。

$dbh = PDODB::getInstance();
$stmt = $dbh->query("CALL ListReached(".$this->item_id.")"); // <-- ERROR
$items = $stmt->fetchAll();

そして、これがMySQLプロシージャの定義です。

DELIMITER $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `ListReached`( IN root INT)
BEGIN
    DECLARE rows SMALLINT DEFAULT 0;

    DROP TABLE IF EXISTS reached;
    CREATE TABLE reached(
    node_id INT PRIMARY KEY
    ) ENGINE=HEAP;

    INSERT INTO reached VALUES (root);
    SET rows = ROW_COUNT();

    WHILE rows > 0 DO
    INSERT IGNORE INTO reached
        SELECT DISTINCT child_id 
        FROM related_item AS r
        INNER JOIN reached AS p ON r.parent_id = p.node_id;
    SET rows = ROW_COUNT();

    INSERT IGNORE INTO reached
        SELECT DISTINCT parent_id
        FROM related_item AS r
        INNER JOIN reached AS p ON r.child_id = p.node_id;
    SET rows = rows + ROW_COUNT();
    END WHILE;

    DELETE FROM reached WHERE node_id = root;

    SELECT * FROM reached;
    DROP TABLE reached;

END
4

1 に答える 1

1

競合状態に陥っています。

2 つの接続が両方とも同じスクリプトを実行している場合、両方が同じテーブルを作成および削除するため、競合が発生します。

トランザクション内で実際のテーブルを作成および削除する代わりに、一時テーブルを使用することを検討してください。

http://dev.mysql.com/doc/refman/5.1/en/create-table.html

テーブルの作成時に TEMPORARY キーワードを使用できます。TEMPORARY テーブルは、現在の接続に対してのみ表示され、接続が閉じられると自動的に削除されます。これは、2 つの異なる接続が、互いに競合したり、同じ名前の既存の非 TEMPORARY テーブルと競合したりすることなく、同じ一時テーブル名を使用できることを意味します。(一時テーブルが削除されるまで、既存のテーブルは非表示になります。) 一時テーブルを作成するには、CREATE TEMPORARY TABLES 権限が必要です。

編集

コメントで述べたように、クエリはテーブルを数回参照しています。

別のアプローチは、プロシージャ内でロックを使用することです: http://dev.mysql.com/doc/refman/5.5/en/miscellaneous-functions.html#function_get-lock

于 2013-01-02T16:28:30.463 に答える