我即将在我的 php 脚本中实现事务,我正在做一些测试以帮助我自己准确地理解它们是如何工作的。我有以下代码片段:
try{
$db->beginTransaction();
$update = "UPDATE persons SET first_name = 'Adam' WHERE person_id = 4";
$stmt = $db->exec($update);
$select = "SELECT person_id, column_that_doesnt_exist FROM persons";
try{
$stmt = $db->prepare($select);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode('success');
} catch (PDOException $e) {
echo 'execute failure';
}
echo ' code gets here';
$db->commit();
} catch(PDOException $e){
$db->rollBack();
echo json_encode('commit failure');
}
哪些输出:
execute failure code gets here
第 4 个人的名字更新为 Adam。
现在我很确定它正在提交,因为第二个查询实际上从未失败过,因为自 prepare
以来它从未真正执行过是失败点。
如果 PDOException
就好了最后被抛出catch
因为一个被扔进了“内部”try
但我可以解决这个问题。
现在如果我取出“内部”try
并有这个代码:
try{
$db->beginTransaction();
$update = "UPDATE persons SET first_name = 'Adam' WHERE person_id = 4";
$stmt = $db->exec($update);
$select = "SELECT person_id, column_that_doesnt_exist FROM persons";
$stmt = $db->prepare($select);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
$db->commit();
} catch(PDOException $e){
$db->rollBack();
echo json_encode('commit failure');
}
提交失败,数据库回滚并输出commit failure
正如预期的那样。
因此在生产中,我是否应该不将每个单独的语句包装在 try-catch
中? ,而是将我所有的陈述都放在一个大的 try
中 block (事务),然后捕获 commit
最后异常(exception)?这对我来说似乎不正确....并且同样不会给你太多关于哪个语句失败的信息......
最佳答案
您使用内部 try..catch block 捕获异常,而不重新抛出它。这意味着该异常已得到处理,并且代码继续进行,就好像没有出错一样,提交事务。
通常这不是理想的解决方案,因为事务主要用于使多个数据修改语句的组合成为原子。通过使用事务,您可以在一切顺利时提交所有内容,或者在出现问题时回滚所有内容。
此外,由于在启动事务本身失败时没有要提交或回滚的内容,因此您应该将其从异常处理中删除。所以正确的结构应该是:
StartTransaction;
try {
ModifyData;
CommitTransaction;
}
catch {
RollbackTransaction;
// Log/mail/show/ignore error
}
如果你想继续插入记录,即使插入其中一条记录失败,你也不需要事务。
如果您想获取有关哪个项目失败的具体信息,您可以重新抛出异常或抛出一个新异常:
StartTransaction;
try {
foreach ($persons as $person) {
try {
ModifyPerson($person);
}
catch {
throw new Exception("Updating person {$person->name} failed");
}
}
CommitTransaction;
}
catch {
RollbackTransaction;
// Log/mail/show/ignore error
}
通过(重新)从内部异常处理程序抛出异常,您可以直接跳转到外部异常处理程序,终止循环并绕过提交。
关于php - 每个语句 VS 的 PDO 异常。一次交易?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22946952/