PHP で MySQL のネストされたトランザクションを実装する方法

不言
リリース: 2023-04-01 06:04:01
オリジナル
1894 人が閲覧しました

この記事では主に PHP で MySQL のネストされたトランザクションを実装するための 2 つのソリューションを紹介します。この記事では doctrine と laravel の実装方法を分析し、分析と要約のために抽出します

1. 問題の原因

MySQL の公式ドキュメントには、ネストされたトランザクションはサポートされていないという明確な記述があります:

Transactions cannot be nested. This is a consequence of the implicit commit performed for any current transaction when you issue a START TRANSACTION statement or one of its synonyms.
ログイン後にコピー

しかし、複雑なシステムを開発する場合、これは避けられません。たとえば、関数 A が関数 B を呼び出し、関数 A がトランザクションを使用し、関数 B にもトランザクションが存在するため、トランザクションのネストが発生することがあります。この時点では、A の事柄は実際にはほとんど重要ではありません。なぜですか。上記のドキュメントで言及されており、簡単に翻訳すると次のようになります。

当执行一个START TRANSACTION指令时,会隐式的执行一个commit操作。
ログイン後にコピー

したがって、システム アーキテクチャ レベルでトランザクションのネストをサポートする必要があります。幸いなことに、Doctrine や Laravel など、一部の成熟した ORM フレームワークではネストがサポートされています。次に、これら 2 つのフレームワークがどのように実装されているかを見てみましょう。

注意してください、これら 2 つのフレームワークにおける関数と変数の名前付けは比較的直感的ですが、非常に長く見えますが、名前付けを通じて関数や変数の意味を直接知ることができるので、心配する必要はありません。このような大きな混乱を見たとき:)

2. Doctrine の解決策

まず、Doctrine でトランザクションを作成するコードを見てみましょう (関連のないコードは強制終了されました) :

public function beginTransaction()
{
    ++$this->_transactionNestingLevel;
    if ($this->_transactionNestingLevel == 1) {
        $this->_conn->beginTransaction();
    } else if ($this->_nestTransactionsWithSavepoints) {
        $this->createSavepoint($this->_getNestedTransactionSavePointName());
    }
}
ログイン後にコピー

この関数の最初の行は、_transactionNestingLevel を使用して現在のネスト レベルを識別し、それが 1 の場合、つまりネストがまだない場合は、デフォルトのメソッドを使用して START TRANSACTION を実行します。これが 1 より大きい場合、つまりネストがある場合、このセーブポイントは、ロールバックが必要な場合にのみ、このポイントまでロールバックできるトランザクション記録ポイントとして理解できます。

次に、rollBack 関数を見てください:

public function rollBack()
{
    if ($this->_transactionNestingLevel == 0) {
        throw ConnectionException::noActiveTransaction();
    }
    if ($this->_transactionNestingLevel == 1) {
        $this->_transactionNestingLevel = 0;
        $this->_conn->rollback();
        $this->_isRollbackOnly = false;
    } else if ($this->_nestTransactionsWithSavepoints) {
        $this->rollbackSavepoint($this->_getNestedTransactionSavePointName());
        --$this->_transactionNestingLevel;
    } else {
        $this->_isRollbackOnly = true;
        --$this->_transactionNestingLevel;
    }
}
ログイン後にコピー

レベルが 1 の場合は直接ロールバックし、それ以外の場合は前のセーブポイントにロールバックする処理方法も非常に単純であることがわかります。

それではコミット関数を見ていきましょう:

public function commit()
{
    if ($this->_transactionNestingLevel == 0) {
        throw ConnectionException::noActiveTransaction();
    }
    if ($this->_isRollbackOnly) {
        throw ConnectionException::commitFailedRollbackOnly();
    }
    if ($this->_transactionNestingLevel == 1) {
        $this->_conn->commit();
    } else if ($this->_nestTransactionsWithSavepoints) {
        $this->releaseSavepoint($this->_getNestedTransactionSavePointName());
    }
    --$this->_transactionNestingLevel;
}
ログイン後にコピー

忘れてください。この段落については簡単に説明しましょう:)

3. Laravel の解決策

Laravel の処理方法は比較的シンプルで大雑把ですが、まずトランザクションを作成する操作を見てみましょう。とても簡単ですよね?まず、現在存在するトランザクションの数を確認します。それが最初のトランザクションである場合、トランザクションは開始されます。それ以外の場合、何も行われないのはなぜでしょうか。引き続き rollBack の操作を見てみましょう:

public function beginTransaction()
{
    ++$this->transactions;
    if ($this->transactions == 1)
    {
        $this->pdo->beginTransaction();
    }
}
ログイン後にコピー

理解できましたか?現在のトランザクションが 1 つだけである場合にのみ、実際にロールバックされます。それ以外の場合は、カウントが 1 つだけデクリメントされます。これが、Laravel の処理が比較的単純で粗雑であると述べた理由です。実際には、ネストされた内側の層には実際のトランザクションは存在しません。最も外側の層には全体的なトランザクションがあるだけです。しかし、これによって問題も解決されます。内部層が新しいトランザクションを作成すると、コミットの問題が発生します。原則は次のとおりです。完全を期すために、コミット コードもコピーしてください。

public function rollBack()
{
    if ($this->transactions == 1)
    {
        $this->transactions = 0;
        $this->pdo->rollBack();
    }
    else
    {
        --$this->transactions;
    }
}
ログイン後にコピー

以上がこの記事の全内容です。その他の関連コンテンツについては、PHP 中国語 Web サイトをご覧ください。


関連する推奨事項:

PHP で mb_detect_encoding 関数を使用する方法


PHP で smtp 送信サポートを使用する方法PHP 添付メール


#PHP の Laravel フレームワークでスーパーバイザー実行の非同期処理を実装する方法


以上がPHP で MySQL のネストされたトランザクションを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート