Transaction

Open transaction

When a transaction is started, all operations between transactions are the same connection. Note that concurrent operations cannot be used.

If you want to start a transaction and have full control over rollback and commit, then you can use DB's beginTransaction method:

 DB::beginTransaction(); 

or

 DB::connection()->beginTransaction(); 

Once the transaction is enabled, the current connection is bound to the current coroutine environment, guaranteeing the 提交 and 回滚 , the 查询 is the same connection to ensure the security of the data, only the 提交 or 回滚 will be unbound.

The transactions of different connection pools are independent of each other. There is no relationship

Transaction rollback

If the operation fails, you need to roll back. You can use the following two methods.

 DB::rollBack(); 

or

 DB::connection()->rollBack(); 

Transaction submission

If the operation is successful, you need to use the following two methods.

 DB::commit(); 

or

 DB::connection()->commit(); 

common problem

Whether the transaction supports nesting

The official MySQL documentation says that if a transaction is nested, the 上一个事务 is implicitly committed and a new transaction is opened.

The answer to the framework is that you can do 事务嵌套 because some databases support the ability to support savepoints . In MySQL, the savepoints belong to the transaction control processing section. With savepoints you can roll back a specified portion of a transaction, making transaction processing more flexible and granular. If you have a transaction nested nested transaction will be saved in savepoints , you can do fine control of nested transactions.

 DB::beginTransaction();
$user = User::find($id);
$user->update(['name' => $id]);

DB::beginTransaction();
User::find($id)->update(['name'=>'sakuraovq']);
DB::rollBack();

DB::commit(); 

嵌套 transaction has been 回滚 , does not affect the 外层 changed data only rollback name=sakuraovq modification, this code is executed name = $id

What if the transaction is not submitted?

 DB::connection()->beginTransaction();
$user = User::find($id);

\sgo(function ()use($id) {
    DB::connection()->beginTransaction();
    User::find($id);
}); 

Code like this if we forget to commit the transaction/rollback.

Swoft checks if the transaction is still in the SwoftEvent::COROUTINE_DEFER event, and if it is, it will automatically rollback to the state where the transaction was originally started. The connection will be returned to the connection pool without causing resource leaks.

Error demonstration

 DB::beginTransaction();
$user = User::find($id);

\sgo(function () use ($id) {
    $user1 = User::find($id);
});
$user->update(['name' => 'sakuraovq'.mt_rand(110,10000)]);
DB::commit();
 

Although code like this has no problem in execution, this kind of writing is wrong and will cause data confusion. Please do not nest the 协程 in the transaction, in the db operation , the above mentioned transaction is bound to the 当前协程 switch coroutine is another new connection.

 DB::connection()->beginTransaction();
$user = User::find($id);
$user->update(['name' => 2]);

\sgo(function () use ($user) {
    $user->update(['name' => 1]);
});
DB::rollBack(); 

This is also wrong, this code will be executed and you will find that the sub-coroutine modification operation rollback is not controlled . Because they use different connections, they are not tied together.

/docs/2.x/en/db/transaction.html
progress-bar