Home  >  Article  >  Backend Development  >  Yii2 development: How to encapsulate transactions in a closure-like manner

Yii2 development: How to encapsulate transactions in a closure-like manner

不言
不言Original
2018-08-14 10:41:131371browse

The content of this article is about Yii2 development: How to encapsulate transactions in a closure-like manner. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

When executing a transaction in the controller, the general code is as follows:

$transaction = Yii::$app->db->beginTransaction();
try {
    //一些业务代码
    $transaction->commit();
} catch (\Exception $e) {
    $transaction->rollBack();
    throw $e;
}

So I was thinking, this code structure, only // some business code parts are different, but it needs to Repeated many times, isn't this redundant? And no! good! look! , so I tried to find a solution. At first I found a similar question on stackflow. There is a solution to encapsulate it in the model, but there are certain problems in doing so, such as nested transactions. If you are interested, you can click here to view the question. Q&A.

Our Yii framework provides a method transaction. At first glance, it seems that it cannot solve the problem of passing parameters. Let’s ignore it for now. Looking down, the method calling method is as follows:

Yii::$app->db->transaction(function() {
    //一些业务代码
});

We Let’s take a look at the source code of this method

/**
 * Executes callback provided in a transaction.
 *
 * @param callable $callback a valid PHP callback that performs the job. Accepts connection instance as parameter.
 * @param string|null $isolationLevel The isolation level to use for this transaction.
 * See [[Transaction::begin()]] for details.
 * @throws \Exception|\Throwable if there is any exception during query. In this case the transaction will be rolled back.
 * @return mixed result of callback function
 */
public function transaction(callable $callback, $isolationLevel = null)
{
    $transaction = $this->beginTransaction($isolationLevel);
    $level = $transaction->level;

    try {
        $result = call_user_func($callback, $this);
        if ($transaction->isActive && $transaction->level === $level) {
            $transaction->commit();
        }
    } catch (\Exception $e) {
        $this->rollbackTransactionOnLevel($transaction, $level);
        throw $e;
    } catch (\Throwable $e) {
        $this->rollbackTransactionOnLevel($transaction, $level);
        throw $e;
    }

    return $result;
}

This method accepts a callback function and the isolation level of the transaction.
From here we can see that although this method solves duplicate code, there are still several problems that have not been solved. :
First, we need to handle the exception thrown by this method outside the reception. We cannot throw it directly, which is very unfriendly to the client.
Second: Without logging, even if a problem occurs, it is not easy to eliminate.
Third: In fact, it is still the first question. If we need to handle each exception and nest a layer of try...catch... outside the transaction method, then it seems to be no different from not encapsulating it?

According to the principle that methods can be extended but not modified, we should overload this method in our own public method. The overloading code is as follows:

public static function TransactionExecute(callable $function,$level=null)
{
    try{
        \Yii::$app->db->transaction($function,$level);
}catch (\Exception $e){
        //记录日志
        \Yii::error($e->getMessage());
        //这里可以理解成抛出自定义的异常类。
        (new self())->returnWayTip(1004, 'trans异常错误');
    }
}

Then back to the question of how to pass parameters, We can use closures and post a piece of pseudo code, as follows:

//执行事务
PublicFunction::TransactionExecute(function () use ($token_reward, $reward_info) {
        //业务代码
        $token_reward->save(0);
    MsgHelper::send($reward_info['post_id'], MsgHelper::SOMEONE_FINISH_REWARD, $reward_info);

    });

Related recommendations:

What are the system settings in php? Summary of commonly used system settings in php (with code)

How does php generate json? PHP method code to generate json

The above is the detailed content of Yii2 development: How to encapsulate transactions in a closure-like manner. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn