如果在Laravel数据库事务中出现异常,会发生什么?

7

我认为这笔交易只是被丢弃了。这个说法准确吗?

我正在使用mysql。

例如:

try {
    DB::beginTransaction();
    throw new Exception("something happened");
    DB::commit()
} catch (Exception $e) {
    Log::debug("something bad happened");
}

谢谢

2个回答

13

如果您正在使用闭包,例如:

DB::transaction(function () {
    DB::table('users')->update(['votes' => 1]);
    DB::table('posts')->delete();
});

您将在框架内运行此代码:

public function transaction(Closure $callback)
{
    $this->beginTransaction();

    // We'll simply execute the given callback within a try / catch block
    // and if we catch any exception we can rollback the transaction
    // so that none of the changes are persisted to the database.
    try {
        $result = $callback($this);

        $this->commit();
    }

    // If we catch an exception, we will roll back so nothing gets messed
    // up in the database. Then we'll re-throw the exception so it can
    // be handled how the developer sees fit for their applications.
    catch (Exception $e) {
        $this->rollBack();

        throw $e;
    } catch (Throwable $e) {
        $this->rollBack();

        throw $e;
    }

    return $result;
}

因此,在这种情况下,您可以100%确定交易将会回滚。如果您手动使用 DB::beginTransaction(); 开启事务,则无法确保它会回滚,除非您通过类似以下方式进行确认:

try {
    DB::beginTransaction();
    //do something
    DB::commit();
} catch (\Exception $e) {
    DB::rollback();
}

如果您在没有捕获异常的情况下抛出异常,脚本将会停止或以打开的事务结束,PDO 将自动回滚 (http://php.net/manual/zh/pdo.transactions.php):

当脚本结束或连接即将关闭时,如果存在未完成的事务,PDO 将自动回滚。


5

没有被提交的事务将在 SQL 中被丢弃。

当您在此处抛出异常时,DB::commit() 永远不会被执行。您将直接进入 catch() 块,因此事务将被丢弃(只要 DB::commit() 在后面没有被调用)。

然而,我仍然建议在 catch 块中显式地回滚事务,如果您不想在抛出异常时提交事务的话。这将关闭该事务并防止对该执行中未来的查询产生任何影响。

try {
    DB::beginTransaction();
    throw new Exception("something happened");
    DB::commit()
} catch (Exception $e) {
    Log::debug("something bad happened");
    DB::rollBack();
}

或者使用内置的DB::transaction()方法,结合闭包函数,在未捕获异常时自动回滚事务。具体文档请参考:https://laravel.com/docs/5.3/database#database-transactions


谢谢。它会保持事务并具有某种清理过程吗? - timbroder
事务将保持开放状态,直到脚本执行结束,此时将进行清理过程来关闭/丢弃该事务。因此,我建议在抛出异常时明确回滚事务。 - Devon
我可以使用Db::commit来表示如果成功执行则输出某些内容吗? - Freddy Sidauruk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接