问题在于:当脚本开始修改数据库并出现问题时,数据库通常会损坏。例如,假设我们有一个User表和一个Photos表。
脚本会创建用户数据集,并在下一行中尝试创建照片数据集。该照片有一个user_id列。现在假设出现问题,PDO的lastInserId()不返回用户的id。那么在最坏的情况下会发生什么:我们得到没有照片的用户,以及没有有效user_id的照片。破碎的参考。调试3周。
是否有任何好的策略可以遵循,以防止这种问题?在下面的代码中,您可以看到我至少尝试将其记录到文件中并退出脚本执行以防止更多损坏和数据库损坏。
public function lastInsertId() {
$id = $this->dbh->lastInsertId();
if (!is_numeric($id)) {
$this->logError("DB::lastInsertId() did not return an id as expected!");
die();
}
return $id;
}
在查询B依赖于查询A的任何时候,也许我必须在整个地方使用事务,等等?这是解决方案吗?
我应该在die()调用之前进行“预防措施回滚”吗?我想在这一点上不会受到太大伤害,不是吗?我不确定......
答案 0 :(得分:5)
解决方案是在每次有多个查询时使用事务,它应该是“全部或全部”,是的 - 这是ACID的 A :原子性。< / p>
如果您愿意,可以在rollback
之前die
进行操作;它不会改变太多(未提交的事务将由数据库引擎自动回滚),但它会使您的代码更清晰,更易于理解。
作为旁注:使用die
这种方式可能不是处理错误的“正确”方法:例如,它会阻止您显示任何类型的“漂亮”错误页面。
更经常使用的解决方案是在出现此类问题时抛出某种异常 - 并且在应用程序的更高层(在一个地方)处理这些例外,显示错误页面。
答案 1 :(得分:1)
除了使用事务引擎(InnoDB,如果你正在使用MySQL,或只是使用PostgreSQL等)并包装相关的原子活动之外,你可以做的事情并不多。< / p>
正如@Seb所说,你可以创建一个事务日志,你甚至可以使用主/从数据库设置,但这在覆盖范围方面并没有真正增加。
答案 2 :(得分:0)
您应该记录所有交易,因此如果自动流程出错(甚至是您的回滚,回退程序等),您仍然可以手动还原所有效果。