【问题标题】:PHP, MySQL, PDO Transactions - Does the code inside try block stop at commit()?PHP、MySQL、PDO 事务 - try 块中的代码是否在 commit() 处停止?
【发布时间】:2016-05-20 08:13:38
【问题描述】:

我对交易很陌生。

以前,我在做的是这样的:

代码块 1

$db = new PDO(...);

$stmt = $db->prepare(...);

if($stmt->execute()){
    // success
    return true;
}else{
    // failed
    return false;
}

但为了将多个查询分组到一个事务中,我现在使用类似的东西:

代码块 2

$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$db->beginTransaction();

try{
    $stmt = $db->prepare(... 1 ...);
    $stmt->execute();

    $stmt = $db->prepare(... 2 ...);
    $stmt->execute();

    $stmt = $db->prepare(... 3 ...);
    $stmt->execute();

    $db->commit();

    return true;
}catch(Exception $e){
    // Failed, maybe write the error to a txt file or something
    $db->rollBack();
    return false;
}

我的问题是:如果事务由于某种原因失败,代码是否停在$db->commit(); 并跳转到catch 块?或者return true; 会先运行,然后它会尝试转到catch?因为如果是这样的话,那我已经回来了,所以它不会去catch。而且它会返回错误的值。

我还需要包含以下内容吗:

代码块 3

if($stmt->commit()){
    return true;
}

还是按照我在代码块 2 中编写的方式就足够了?

【问题讨论】:

  • 是的,如果代码在$db->commit(); 处停止,则将返回catch 块的输出,因此您无需添加if($stmt->commit()) .... php.net/manual/en/pdo.transactions.php 之类的条件

标签: php mysql pdo transactions


【解决方案1】:

如果事务由于某种原因失败,代码确实会停止在发生错误的那一行结束,然后执行直接跳转到 catch 块。因此,在代码块 2 中编写它的方式就足够了。

请注意,您应该在回滚后始终重新抛出异常。否则您将永远不知道出了什么问题。所以应该是

try{
    $stmt = $db->prepare(... 1 ...);
    $stmt->execute();

    $stmt = $db->prepare(... 2 ...);
    $stmt->execute();

    $stmt = $db->prepare(... 3 ...);
    $stmt->execute();

    $db->commit();

    return true;
}catch(Exception $e){
    $db->rollBack();
    throw $e;
}

【讨论】:

  • throw $e; 到底是做什么的?我不能只通过$e->getMessage() 访问异常吗?
  • 你可以,但你不应该。异常不应该就地处理。是编程。您应该只编写一次处理代码,而不是每次运行查询时都编写它。此外,如果有一天你会改变主意,并且会有另一个想法来处理除了记录之外的错误吗?是否会进行大规模重写?
  • 此外,说到这种特殊情况,PHP 已经可以为您记录错误。意思是,如果你需要登录,你不必写一行,只需要ini_set('log_errors', 1);一个
  • 是的,是我。我写它主要是因为周围有很多不好的例子,教人们以错误的方式处理异常。很高兴你喜欢它!
  • 我的知识远比你想象的要少。要被称为神,需要知道十倍的知识。说到我自己,我只是痴迷于分享知识,有点沉迷于 SO。
【解决方案2】:

抛出异常时停止执行。

不会到达第一个返回但会执行catch语句。

你甚至可以直接返回提交:

$dbh->beginTransaction();
try {
    // insert/update query
    return $dbh->commit();
} catch (PDOException $e) {
     $dbh->rollBack();
     return false;
}

【讨论】:

    【解决方案3】:

    如果您遇到任何错误,您可以这样做以回滚所有此类事务

    catch(Exception $e){
        $db->rollBack();
        // Failed, maybe write the error to a txt file or something
        return false;
    }
    

    【讨论】:

    • 阿米特,谢谢。我忘了把那一行放在问题中,但它在我的代码中。但是你的回答并没有解决我的问题。回滚不是我关心的问题,而是可能存在于$stmt->commit(); 行之外的任何代码。
    • 如果您的任何事务代码失败,它将进入您的 catch 块。将执行 catch 块中的任何代码。
    猜你喜欢
    • 2012-03-24
    • 1970-01-01
    • 2016-09-18
    • 2016-09-18
    • 2021-12-25
    • 2015-08-10
    • 2012-06-17
    • 2014-11-21
    • 2023-01-25
    相关资源
    最近更新 更多