我们都使用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;
答案 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兼容,请使用Exception
和Throwable
:
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_at
,created_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();
}