Laravel:使用try ... catch DB :: transaction()

时间:2014-04-07 08:09:14

标签: php laravel transactions

我们都使用DB::transaction()进行多次插入查询。这样做,try...catch是否应放在其中或包裹它?如果出现问题,甚至有必要在事务自动失败时包含try...catch吗?

包装交易的示例try...catch

// try...catch
try {
    // Transaction
    $exception = DB::transaction(function() {

        // Do your SQL here

    });

    if(is_null($exception)) {
        return true;
    } else {
        throw new Exception;
    }

}
catch(Exception $e) {
    return false;
}

相反,DB::transaction()包装尝试... catch:

// Transaction
$exception = DB::transaction(function() {
    // try...catch
    try {

        // Do your SQL here

    }
    catch(Exception $e) {
        return $e;
    }

});

return is_null($exception) ? true : false;

或者只是一个没有尝试的交易......抓住

// Transaction only
$exception = DB::transaction(function() {

    // Do your SQL here

});

return is_null($exception) ? true : false;

6 个答案:

答案 0 :(得分:118)

如果您需要通过代码手动“退出”事务(通过异常或只是检查错误状态),您不应该使用DB::transaction(),而是将代码包装在{{1}中}和DB::beginTransaction / DB::commit

DB::rollback()

请参阅transaction docs

答案 1 :(得分:13)

如果您使用PHP7,请使用catch中的Throwable来捕获用户异常和致命错误。

例如:

DB::beginTransaction();

try {
    DB::insert(...);    
    DB::commit();
} catch (\Throwable $e) {
    DB::rollback();
    throw $e;
}

如果您的代码必须与PHP5兼容,请使用ExceptionThrowable

DB::beginTransaction();

try {
    DB::insert(...);    
    DB::commit();
} catch (\Exception $e) {
    DB::rollback();
    throw $e;
} catch (\Throwable $e) {
    DB::rollback();
    throw $e;
}

答案 2 :(得分:8)

你可以通过try..catch包装交易甚至反转它们, 这里是我在laravel 5中使用的示例代码,如果你深入find /opt/logs -type ...中的DB:transaction(),就像你编写手动事务一样,

Laravel Transaction

Illuminate\Database\Connection

因此您可以像这样编写代码,并通过flash或重定向到另一个页面来处理您的异常,例如将消息抛回到表单中。 REMEMBER返回内部闭包是在transaction()中返回的,所以如果你返回public function transaction(Closure $callback) { $this->beginTransaction(); try { $result = $callback($this); $this->commit(); } catch (Exception $e) { $this->rollBack(); throw $e; } catch (Throwable $e) { $this->rollBack(); throw $e; } return $result; } 它将不会立即重定向,因为它在处理事务的变量处返回。

包装交易

redirect()->back()

然后替代方法是抛出布尔变量并处理事务函数外的重定向,或者如果需要检索事务失败的原因,可以从$result = DB::transaction(function () use ($request, $message) { try{ // execute query 1 // execute query 2 // .. return redirect(route('account.article')); } catch (\Exception $e) { return redirect()->back() ->withErrors(['error' => $e->getMessage()); } }); // redirect the page return $result; $e->getMessage()内的catch(Exception $e){...}获取它

答案 3 :(得分:0)

我决定为这个问题提供一个答案,因为我认为可以使用比卷积try-catch块更简单的语法来解决它。 Laravel文档对此主题非常简短。

您可以像这样使用DB::transaction(){...}包装器来代替try-catch:

// MyController.php
public function store(Request $request) {
    return DB::transaction(function() use ($request) {
        $user = User::create([
            'username' => $request->post('username')
        ]);

        // Add some sort of "log" record for the sake of transaction:
        $log = Log::create([
            'message' => 'User Foobar created'
        ]);

        // Lets add some custom validation that will prohibit the transaction:
        if($user->id > 1) {
            throw AnyException('Please rollback this transaction');
        }

        return response()->json(['message' => 'User saved!']);
    });
};

然后您应该看到User和Log记录不能彼此不存在。

关于上述实现的一些说明:

  • 请确保return进行交易,以便您可以使用在其回调中返回的response()
  • 如果您要回滚事务,请确保throw是一个异常(或者有一个嵌套函数可以自动为您抛出异常,例如Eloquent中的SQL异常)。
  • id对象(在此事务期间)的updated_atcreated_at$user和其他任何字段在创建后都可用。事务将通过您拥有的任何创建逻辑来运行。但是,抛出AnyException时会丢弃整个记录。这意味着,例如id的自动增量列在失败的事务中的确增加。

在Laravel 5.8上测试

答案 4 :(得分:0)

在 laravel 8 中,你可以在 try-catch 中使用 DB::transaction。 例如:

try{
    DB::transaction(function() {
        // do anything
    });
}
catch(){
    // do anything
}

如果每个查询都失败了,则运行 catch 块。

答案 5 :(得分:0)

我知道这之前可能已经得到了很好的回答,但我想提供支持:D。

我有时会这样做。

try {
    DB::transaction(function () use (/* place here extra variables if you need */) {
        throw new Exception("Hubo un error en la transacción");
    });
    // If no errors, you can continue with your common workflow.
} catch (Exception $e) {
    // You can check here because the transaction will auto rollback and then will throw an exception.
    return $e->getMessage();
}