我正在使用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
答案 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