我们遇到以下情况。。。
DROP PROCEDURE IF EXISTS unit_throw_error;
CREATE PROCEDURE unit_throw_error() CALL throw_error();
DROP PROCEDURE IF EXISTS throw_error;
CREATE PROCEDURE throw_error() CALL _proc_does_not_exist();
如果调用第一个过程unit_throw_error
,php-PDO对象将不会抛出通过第二个过程创建的异常。一些示例代码:
$dsn = "mysql:host=localhost;dbname=test";
$username = "...";
$password = "...";
$pdo = new PDO($dsn, $username, $password, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$query = "CALL unit_throw_error();";
$stmt = $pdo->prepare($query);
$stmt->execute();
do {
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
} while ($stmt->nextRowset() && $stmt->columnCount());
$stmt->closeCursor();
预期的结果是抛出的PDOException
,但这并没有发生。有什么想法吗?
编辑
我们已经将这种情况隔离为只有在抛出异常的行之前成功选择时才会发生。。。
-- CREATE DATABASE `exception_test` /*!40100 DEFAULT CHARACTER SET utf8 */;
use exception_test;
DROP TABLE if exists `test_data`;
CREATE TABLE `test_data` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`some_field` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `test_data` (`some_field`) VALUES ('sdf');
INSERT INTO `test_data` (`some_field`) VALUES ('fgh');
INSERT INTO `test_data` (`some_field`) VALUES ('ghj');
drop procedure if exists `unit_throw_error`;
create procedure unit_throw_error() call unit_throw_error_2();
drop procedure if exists `unit_throw_error_2`;
delimiter //
create procedure unit_throw_error_2()
begin
select * from test_data;
call unknown_procedure();
end//
delimiter ;
有人知道当选择查询导致异常不被抛出时的原因吗?
在处理存储过程时,需要调用next_result()
方法,以便让PDO知道该过程返回的其他结果。
所以,代码应该是
$stmt = $pdo->prepare("CALL unit_throw_error()");
$stmt->execute();
do {
$data = $stmt->fetchAll();
var_dump($data);
} while ($stmt->nextRowset() && $stmt->columnCount());
在这种情况下,PDO将从数据库中获取下一个结果,如果此结果是错误,则将抛出异常。
编辑:
对于语法错误的这种特殊情况(即甚至在执行之前发生的错误),实际上不需要调用nextRowset()
。相反,只需确保PDO设置为ERRMODE_EXCEPTION
即可。
但是,无论如何,必须使用存储过程调用nextRowset()
,以便运行其他查询,并在预期有多个结果集的情况下获得错误。
所以(只是为了证明我的答案有用),如果你把代码改成这样:
drop procedure if exists `unit_throw_error`;
create procedure unit_throw_error() call unit_throw_error_2();
drop procedure if exists `unit_throw_error_2`;
delimiter //
create procedure unit_throw_error_2()
begin
select * from test_data;
select * from non_existent;
end//
delimiter ;
并在没有nextRowset()
调用的情况下运行PDO代码,不会出现任何错误。但是我在上面发布的代码会抛出错误,
SQLSTATE[42S02]:找不到基表或视图:1146表"exception_test.non_existent"不存在