使用DROP TABLE IF EXISTS的PDOException

时间:2013-01-02 16:01:34

标签: php mysql pdo

我正在使用PDO来调用以DROP TABLE IF EXISTS开头的存储过程。我随机获取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

1 个答案:

答案 0 :(得分:1)

你正在遇到竞争状态。

如果两个连接都在执行相同的脚本,它们将同时创建和删除相同的表,从而导致冲突。

考虑使用临时表,而不是在事务中创建和删除真实表。

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

  

创建表时可以使用TEMPORARY关键字。 TEMPORARY表仅对当前连接可见,并在关闭连接时自动删除。这意味着两个不同的连接可以使用相同的临时表名,而不会相互冲突或与现有的同名非TEMPORARY表冲突。 (在删除临时表之前,将隐藏现有表。)要创建临时表,您必须具有CREATE TEMPORARY TABLES权限。

修改

正如评论中提到的那样,查询几次引用该表。

另一种方法是在过程中使用锁:http://dev.mysql.com/doc/refman/5.5/en/miscellaneous-functions.html#function_get-lock