我即将在我的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');
}
提交失败,db回滚并按预期输出commit failure
。
所以在生产中,我应该 NOT 将每个单独的语句包装在try-catch
中,而是将我的所有语句都放在一个大的try
块(事务)中,然后最后抓住commit
例外?这对我来说似乎不对......而且同样不会给你很多关于哪个陈述失败的信息......
答案 0 :(得分:1)
使用内部try..catch块捕获异常,而无需重新抛出它。这意味着处理该异常,并且代码继续,好像什么都没有出错,提交事务。
通常这不是理想的解决方案,因为事务主要用于将多个数据修改语句组合成原子。通过使用事务,如果一切顺利,您可以提交所有内容,或者在出现问题时回滚所有内容。
此外,由于在启动事务本身失败时无法提交或回滚,因此您应该将其从异常处理中拉出来。所以适当的结构将是:
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
}
通过(重新)从内部异常处理程序抛出异常,您直接跳转到外部异常处理程序,终止循环,并绕过提交。
答案 1 :(得分:0)
删除内部的try catch块。
使用echo $ e-> getMessage()获取错误信息; //注意不要在关键点或功能(对用户)中显示消息,因为此消息可能会显示数据库信息甚至是密码。
在这种特定情况下,您无法按照自己的方式获取更多详细信息。为什么一个人失败而另一个人失败? 但是做一些事情,比如首先获取所有行,然后逐个更新1(这里有一个内部的try catch或保存当前行),以获得给出错误的特定行,我认为更多。