ホームページ  >  記事  >  バックエンド開発  >  PHP で MySQL のネストされたトランザクションを実装するための 2 つのソリューション

PHP で MySQL のネストされたトランザクションを実装するための 2 つのソリューション

WBOY
WBOYオリジナル
2016-08-08 09:25:19992ブラウズ

1. 問題の原因

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

1. トランザクションはネストできません。これは、START TRANSACTION ステートメントまたはそのシノニムの 1 つを発行するときに、現在のトランザクションに対して実行される暗黙的なコミットの結果です。

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

1. START TRANSACTION 命令を実行すると、暗黙的にコミット操作が実行されます。 したがって、システム アーキテクチャ レベルでトランザクションのネストをサポートする必要があります。

幸いなことに、doctrine や laravel など、一部の成熟した ORM フレームワークはネストをサポートしています。次に、これら 2 つのフレームワークがどのように実装されているかを見てみましょう。これら 2 つのフレームワークにおける関数と変数の名前付けは比較的直感的ですが、名前を付けることで関数や変数の意味を直接知ることができるので、一見しただけではそれほど混乱する必要はありません。とても怖かったです:)

2. ドクトリンの解決策

まず、Doctrine でトランザクションを作成するコードを見てみましょう (無関係なコードは削除されました):

[php] プレーンコピーを表示

  1. /**  
  2. * 著者 http://www.lai18.com
  3. * 日付 2015-04-19
  4. * バージョン 1
  5. **/
  6. public functionbeginTransaction()
  7. {
  8. ++$this->_transactionNestingLevel
  9. } else
  10. if
  11. ($this->_nestTransactionsWithSavepoints) {
  12. これ以上はありません }
  13. }
  14. この関数の最初の行は、_transactionNestingLevel を使用して現在のネスト レベルを識別します。それが 1 の場合、つまりネストがまだない場合は、デフォルトのメソッドを使用して START TRANSACTION を実行します。それが大きい場合は問題ありません。 1 よりも、つまり、ネストがある場合、このセーブポイントは、ロールバックが必要な場合、このポイントまでしかロールバックできない、トランザクション記録ポイントとして理解できます。次に、rollBack 関数を見てみましょう: [php] プレーンコピーを表示
    1. 1. /**  
    2. * 著者 http://www.lai18.com
    3. * 日付 2015-04-19
    4. * バージョン 1
    5. **/
    6. public function rollBack()
    7. {
    8. if ($this->_transactionNestingLevel == 0) {
    9. throw ConnectionException::noActiveTransaction();  
    10. }
    11. if ($this->_transactionNestingLevel == 1) {
    12. $this->_transactionNestingLevel = 0;  
    13. $this->_conn->rollback();  
    14. $this->_isRollbackOnly = false;  
    15. } else if ($this->_nestTransactionsWithSavepoints) {
    16. $this->rollbackSavepoint($this->_getNestedTransactionSavePointName());  
    17. --$this->_transactionNestingLevel;  
    18. } else {
    19. $this->_isRollbackOnly = true;  
    20. --$this->_transactionNestingLevel;  
    21. }
    22. }

    処理方法も非常に単純で、レベルが 1 の場合は、前のセーブポイントに戻るかどうかを直接ロールバックします。

    [php] プレーンコピーを表示

    1. 1. /**  
    2. * 著者 http://www.lai18.com
    3. * 日付 2015-04-19
    4. * バージョン 1
    5. **/
    6. public function commit()
    7. {
    8. if ($this->_transactionNestingLevel == 0) {
    9. throw ConnectionException::noActiveTransaction();  
    10. }
    11. if ($this->_isRollbackOnly) {
    12. throw ConnectionException::commitFailedRollbackOnly();  
    13. }
    14. if ($this->_transactionNestingLevel == 1) {
    15. $this->_conn->commit();  
    16. } else if ($this->_nestTransactionsWithSavepoints) {
    17. $this->releaseSavepoint($this->getNestedTransactionSavePointName());  
    18. }
    19. --$this->_transactionNestingLevel;  
    20. }

    算了,不费口舌解释段了吧 :)

    三、laravel の解決方法laravel の処理方法は、相対的に荒々しい暴挙であり、以下の構築業務の操作:

    [php] プレーンコピーを表示

    1. 1.
    2. /**  
    3. * 著者 http://www.lai18.com
    4. * 日付 2015-04-19
    5. * バージョン 1
    6. **/
    7. public function beginTransaction()
    8. {
    9. ++$this->トランザクション;  
    10. if ($this->トランザクション == 1)
    11. {
    12. $this->pdo->beginTransaction();  
    13. }
    14. }

    感觉どうやって?とても簡単です?先判断当前有几个事务、如果是第一、ok、事务開始、否则就啥都不做、那么是啥是啥都不做呢?继续往下看ロールバック的操作:

    [php] プレーンコピーを表示

    1. 1. /**  
    2. * 著者 http://www.lai18.com
    3. * 日付 2015-04-19
    4. * バージョン 1
    5. **/
    6. パブリック 関数 rollBack()
    7. {
    8. _
    9. }
    10. }
    11. }
    12. わかりますか?現在のトランザクションが 1 つだけである場合にのみ、実際にロールバックされます。それ以外の場合は、カウントが 1 つだけデクリメントされます。これが、Laravel の処理が比較的単純で粗雑であると述べた理由です。実際には、ネストされた内側の層には実際のトランザクションは存在しません。最も外側の層には全体的なトランザクションがあるだけです。しかし、これによって問題も解決されます。内部層が新しいトランザクションを作成すると、コミットの問題が発生します。原則は次のとおりです。完全を期すために、コミット コードもコピーしてください。
    13. [php] プレーンコピーを表示
    14. パブリック 関数
    15. commit()
    16. {

      }
    1. 上記では、PHP で MySQL のネストされたトランザクションを実装するための 2 つのソリューションを、関連する側面も含めて紹介しました。PHP チュートリアルに興味のある友人にとって役立つことを願っています。
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。