enc*_*nce 61 php transactions laravel
我们都使用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;
}
Run Code Online (Sandbox Code Playgroud)
相反,DB::transaction()包装尝试...抓住:
// Transaction
$exception = DB::transaction(function() {
// try...catch
try {
// Do your SQL here
}
catch(Exception $e) {
return $e;
}
});
return is_null($exception) ? true : false;
Run Code Online (Sandbox Code Playgroud)
或者只是一个没有尝试的交易......捕获
// Transaction only
$exception = DB::transaction(function() {
// Do your SQL here
});
return is_null($exception) ? true : false;
Run Code Online (Sandbox Code Playgroud)
ale*_*ell 142
如果您需要通过代码手动"退出"事务(通过异常或只是检查错误状态),您不应该使用DB::transaction(),而是将代码包装在/ DB::beginTransaction和:DB::commitDB::rollback()
DB::beginTransaction();
try {
DB::insert(...);
DB::insert(...);
DB::insert(...);
DB::commit();
// all good
} catch (\Exception $e) {
DB::rollback();
// something went wrong
}
Run Code Online (Sandbox Code Playgroud)
查看交易文档.
mnv*_*mnv 18
如果你使用PHP7,使用的Throwable在catch捕捉用户异常和致命错误.
例如:
DB::beginTransaction();
try {
DB::insert(...);
DB::commit();
} catch (\Throwable $e) {
DB::rollback();
throw $e;
}
Run Code Online (Sandbox Code Playgroud)
如果您的代码必须与PHP5兼容,请使用Exception和Throwable:
DB::beginTransaction();
try {
DB::insert(...);
DB::commit();
} catch (\Exception $e) {
DB::rollback();
throw $e;
} catch (\Throwable $e) {
DB::rollback();
throw $e;
}
Run Code Online (Sandbox Code Playgroud)
Fla*_*ame 10
我决定回答这个问题,因为我认为可以使用比复杂的 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!']);
});
};
Run Code Online (Sandbox Code Playgroud)
您应该看到,在此设置中,用户和日志记录不能单独存在。
关于上述实现的一些注意事项:
return事务的任何内容,以便您可以使用response()在其回调中返回的内容作为控制器的响应。throw如果您希望事务回滚,请确保异常(或者有一个嵌套函数自动为您抛出异常,就像 Eloquent 中的任何 SQL 异常一样)。id字段在创建对象后可用(至少在此事务的持续时间内)。该事务将通过您拥有的任何创建逻辑运行。但是,抛出时整个记录将被丢弃。尽管事务失败,但自动增量列确实会增加。updated_atcreated_at$userSomeCustomExceptionid在 Laravel 5.8 上测试
您可以将事务包装在try..catch上,甚至可以反转它们,这里是我在laravel 5中使用的示例代码,如果您深入了解内部DB:transaction(),Illuminate\Database\Connection就像您编写手动事务一样,
Laravel交易
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;
}
Run Code Online (Sandbox Code Playgroud)
所以你可以像这样写你的代码,并处理你的异常,例如通过flash将信息扔回你的表单或重定向到另一个页面.REMEMBER返回内部闭包是在transaction()中返回的,所以如果你返回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;
Run Code Online (Sandbox Code Playgroud)
然后替代方法是抛出布尔变量并处理事务函数外的重定向,或者如果您需要检索为什么事务失败,您可以从$e->getMessage()内部获取它catch(Exception $e){...}
我使用的是 Laravel 8,您应该将事务包装在 try-catch 中,如下所示:
try {
DB::transaction(function () {
// Perform your queries here using the models or DB facade
});
}
catch (\Throwable $e) {
// Do something with your exception
}
Run Code Online (Sandbox Code Playgroud)