php Laravel:在 DB::transaction() 中使用 try...catch
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22906844/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Laravel: Using try...catch with DB::transaction()
提问by enchance
We all use DB::transaction()
for multiple insert queries. In doing so, should a try...catch
be placed inside it or wrapping it? Is it even necessary to include a try...catch
when a transaction will automatically fail if something goes wrong?
我们都DB::transaction()
用于多个插入查询。这样做时,应该将 atry...catch
放在里面还是包裹它?try...catch
如果出现问题,是否有必要包含一个事务何时会自动失败?
Sample try...catch
wrapping a transaction:
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;
}
The opposite, a DB::transaction()
wrapping a try...catch:
相反,一个DB::transaction()
包裹一个 try...catch:
// Transaction
$exception = DB::transaction(function() {
// try...catch
try {
// Do your SQL here
}
catch(Exception $e) {
return $e;
}
});
return is_null($exception) ? true : false;
Or simply a transaction w/o a try...catch
或者只是一个没有 try...catch 的交易
// Transaction only
$exception = DB::transaction(function() {
// Do your SQL here
});
return is_null($exception) ? true : false;
回答by alexrussell
In the case you need to manually 'exit' a transaction through code (be it through an exception or simply checking an error state) you shouldn't use DB::transaction()
but instead wrap your code in DB::beginTransaction
and DB::commit
/DB::rollback()
:
如果您需要通过代码手动“退出”事务(无论是通过异常还是简单地检查错误状态),您不应该使用DB::transaction()
,而是将代码包装在DB::beginTransaction
和DB::commit
/ 中DB::rollback()
:
DB::beginTransaction();
try {
DB::insert(...);
DB::insert(...);
DB::insert(...);
DB::commit();
// all good
} catch (\Exception $e) {
DB::rollback();
// something went wrong
}
See the transaction docs.
请参阅交易文档。
回答by mnv
If you use PHP7, use Throwablein catch
for catching user exceptions and fatal errors.
如果你使用PHP7,使用的Throwable在catch
捕捉用户异常和致命错误。
For example:
例如:
DB::beginTransaction();
try {
DB::insert(...);
DB::commit();
} catch (\Throwable $e) {
DB::rollback();
throw $e;
}
If your code must be compartable with PHP5, use Exception
and Throwable
:
如果您的代码必须与 PHP5 兼容,请使用Exception
和Throwable
:
DB::beginTransaction();
try {
DB::insert(...);
DB::commit();
} catch (\Exception $e) {
DB::rollback();
throw $e;
} catch (\Throwable $e) {
DB::rollback();
throw $e;
}
回答by Angga Ari Wijaya
You could wrapping the transaction over try..catch or even reverse them,
here my example code I used to in laravel 5,, if you look deep inside DB:transaction()
in Illuminate\Database\Connection
that the same like you write manual transaction.
您可以通过 try..catch 包装事务,甚至可以反转它们,这里是我在 laravel 5 中使用的示例代码,如果您深入了解内部DB:transaction()
,Illuminate\Database\Connection
就像编写手动事务一样。
Laravel Transaction
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;
}
so you could write your code like this, and handle your exception like throw message back into your form via flash or redirect to another page. REMEMBER return inside closure is returned in transaction() so if you return redirect()->back()
it won't redirect immediately, because the it returned at variable which handle the transaction.
所以你可以像这样编写你的代码,并处理你的异常,比如通过 flash 将消息扔回你的表单或重定向到另一个页面。记住闭包内部的返回在 transaction() 中返回,因此如果您返回redirect()->back()
它,它不会立即重定向,因为它在处理事务的变量处返回。
Wrap Transaction
包装交易
$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;
then the alternative is throw boolean variable and handle redirect outside transaction function or if your need to retrieve why transaction failed you can get it from $e->getMessage()
inside catch(Exception $e){...}
那么另一种方法是抛出布尔变量并处理外部事务函数的重定向,或者如果您需要检索事务失败的原因,您可以从$e->getMessage()
内部获取它catch(Exception $e){...}
回答by Flame
I've decided to give an answer to this question because I think it can be solved using a simpler syntax than the convoluted try-catch block. The Laravel documentation is pretty brief on this subject.
我决定回答这个问题,因为我认为它可以使用比复杂的 try-catch 块更简单的语法来解决。Laravel 文档对这个主题非常简短。
Instead of using try-catch, you can just use the DB::transaction(){...}
wrapper like this:
您可以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!']);
});
};
You should then see that the User and the Log record cannot exist without eachother.
然后您应该看到 User 和 Log 记录不能没有彼此。
Some notes on the implementation above:
关于上述实现的一些注意事项:
- Make sure to
return
the transaction, so that you can use theresponse()
you return within its callback. - Make sure to
throw
an exception if you want the transaction to be rollbacked (or have a nested function that throws the exception for you automatically, like an SQL exception from within Eloquent). - The
id
,updated_at
,created_at
and any other fields are AVAILABLE AFTER CREATION for the$user
object (for the duration of this transaction). The transaction will run through any of the creation logic you have. HOWEVER, the whole record is discarded when theAnyException
is thrown. This means that for instance an auto-increment column forid
does get incremented on failed transactions.
- 确保
return
交易,以便您可以response()
在其回调中使用您返回的内容。 throw
如果您希望事务被回滚(或者有一个嵌套函数为您自动抛出异常,比如 Eloquent 中的 SQL 异常),请确保出现异常。- 的
id
,updated_at
,created_at
和任何其它字段是为可用之后CREATION$user
对象(此事务处理的持续时间)。事务将通过您拥有的任何创建逻辑运行。但是,当AnyException
抛出时,整个记录都会被丢弃。这意味着,例如,对于id
失败的事务,自动增量列确实会增加。
Tested on Laravel 5.8
在 Laravel 5.8 上测试