2013-01-02 149 views
3

我正在使用PDO调用以DROP TABLE IF EXISTS开头的存储过程。我随机得到PDOException'SQLSTATE [42S02]:未找到基本表或视图:1146表'historygr.reached'不存在',甚至更烦人它会告诉我,抛出一个异常说,表已经存在,几秒钟之内,似乎从相同的连接。PDOException与DROP TABLE IF EXISTS

我不能自己触发错误,但我得到它的错误通知。

下面是错误的起源于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

你打比赛的条件。

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

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

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

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

编辑

正如评论mentionned,查询正在引用多个时间表。

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

+0

遗憾的是不能使用一个临时表,因为你不能引用他们不止一次在查询这是何等的程序功能 –

+0

呀,你会需要创建一个临时表的副本来多次引用它(每个引用n-1个副本),或者更改您的查询,而不是多次引用临时表。 –