这是我的剧本:
try{
$db_conn->beginTransaction();
$stm1 = $db_conn->prepare("UPDATE table1 SET col = 'updated' WHERE id = ?");
$stm1->execute(array($value));
$done = $stm->rowCount();
if ($done){
try {
$stm2 = $db_conn->prepare("INSERT into table2 (col) VALUES (?)");
$stm2->execute(array($id));
} catch(PDOException $e){
if ((int) $e->getCode() === 23000) { // row is duplicate
$stm3 = $db_conn->prepare("DELETE FROM table2 WHERE col = ?");
$stm3->execute(array($id));
} else {
$db_conn->rollBack(); -- this
}
}
} else {
$error = true;
}
$db_conn->commit();
}
catch(PDOException $e){
$db_conn->rollBack();
}
如您所见rollBack()
之前有commit()
(我已-- this
评论)。那是我正确的做法吗?或者rollBack()
没用?
注意: DELETE
语句用作撤消操作。假设你对一篇文章进行投票,你想要收回它。因此,如果您发送两次投票,DELETE
语句会将其删除。
答案 0 :(得分:2)
你不需要让它变得如此复杂。
您可以在单个try/catch
内运行2个查询,因为任何具有isse的查询都会抛出异常,然后您可以执行单个回滚。
如果第一个查询失败,则不会更改数据库,回滚只会关闭事务。如果第二个查询失败,则回滚将取消第一个查询,即您之前执行的更新。
如果两个查询都完成OK,则提交会将更改应用于数据库。
try{
$db_conn->beginTransaction();
$stm1 = $db_conn->prepare("UPDATE table1 SET col = 'updated' WHERE id = ?");
$stm1->execute(array($value));
$stm2 = $db_conn->prepare("INSERT into table2 (col) VALUES (?)");
$stm2->execute(array($id));
$db_conn->commit();
}
catch(PDOException $e){
$db_conn->rollBack();
}
其他说明
我看到你认为你想要做的事情。但是!
如果INSERT失败并显示23000
错误代码,则INSERT将不会完成。您不必要的尝试删除失败的INSERT实际上会删除原来的行,即不应删除的原始投票!
答案 1 :(得分:1)
您的代码可以正常运行。如果要重新抛出错误(这将是“标准方式”),您可以摆脱内部回滚:
try {
...
if ($done){
try {
...
} catch(PDOException $e){
if ((int) $e->getCode() === 23000) { // row is duplicate
...
} else {
throw $e;
}
}
...
} else {
$error = true;
}
$db_conn->commit();
}
catch(PDOException $e){
$db_conn->rollBack();
}
在这种情况下,您的最终rollback
将处理所有应该回滚的异常,同时自己处理一个例外23000
而不回滚。
它也适用于您的代码。从技术上讲,您实际上可以根据需要组合尽可能多的commits
和rollbacks
,而不会导致错误 - 如果commit
之后rollback
,它将不会提交任何内容,因为它已经回滚了。如果您使用rollback
而不使用start transaction
(在自动提交模式下),它将不执行任何操作。维护代码和查看strcuture有点困难,这就是为什么你通常会使用上面的“标准方式”。
只需要考虑一件重要的事情:mysql中的事务不是嵌套的。如果您使用start transaction
,则会在此之前自动执行commit
。例如,
start transaction;
delete from very_important_table;
start transaction; -- will do an autocommit
rollback;
rollback; -- will have no effect;
commit; -- will have no effect;
rollback; -- will have no effect;
不会回滚您的very_import_table
,因为第二个start transaction
已经提交了它。