Maison > base de données > tutoriel mysql > Implémentation de transactions imbriquées MySQL

Implémentation de transactions imbriquées MySQL

黄舟
Libérer: 2017-02-06 10:56:14
original
1789 Les gens l'ont consulté

1. Origine du problème

La documentation officielle de MySQL indique clairement que les transactions imbriquées ne sont pas prises en charge :

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.
Copier après la connexion

Mais lorsque nous développons un système complexe, il est inévitable que nous le fassions Si vous le faites accidentellement, il y a une transaction imbriquée dans la transaction. Par exemple, la fonction A appelle la fonction B, la fonction A utilise une transaction et la fonction B est appelée dans la transaction. La fonction B a également une transaction, donc l'imbrication des transactions se produit. À l’heure actuelle, les affaires de A n’ont en réalité que peu d’importance. Pourquoi ? C'est mentionné dans le document ci-dessus. Une traduction simple est :

Lorsqu'une instruction START TRANSACTION est exécutée, une opération de validation sera implicitement exécutée.

Nous devons donc prendre en charge l'imbrication des transactions au niveau de l'architecture du système. Heureusement, certains frameworks ORM matures prennent en charge l'imbrication, comme Doctrine ou Laravel. Voyons ensuite comment ces deux frameworks sont implémentés.

Rappel amical, la dénomination des fonctions et des variables dans ces deux frameworks est relativement intuitive Bien que cela semble très long, vous pouvez connaître directement la signification de la fonction ou de la variable grâce à la dénomination, alors n'ai-je pas eu peur. quand j'ai vu un si gros gâchis :)

2. La solution de Doctrine

Tout d'abord, jetons un coup d'œil au code pour créer des transactions dans Doctrine (code non pertinent supprimé) :

publicfunctionbeginTransaction(){
    ++$this->_transactionNestingLevel;    
    if ($this->_transactionNestingLevel == 1) {        
    $this->_conn->beginTransaction();
    } elseif ($this->_nestTransactionsWithSavepoints) {        
    $this->createSavepoint($this->_getNestedTransactionSavePointName());
    }
}
Copier après la connexion

La première ligne de cette fonction utilise un _transactionNestingLevel pour identifier le niveau d'imbrication actuel. S'il est 1, c'est-à-dire qu'il n'y a pas encore d'imbrication, alors utilisez la méthode par défaut pour exécuter START TRANSACTION et tout ira bien. il est supérieur à 1, c'est-à-dire qu'en cas d'imbrication, elle nous aidera à créer un point de sauvegarde. Ce point de sauvegarde peut être compris comme un point d'enregistrement de transaction. Lorsqu'une restauration est nécessaire, vous ne pouvez revenir qu'à ce point.

Regardez ensuite la fonction rollBack :

publicfunctionrollBack(){    
if ($this->_transactionNestingLevel == 0) {        
throw ConnectionException::noActiveTransaction();
    }    
    if ($this->_transactionNestingLevel == 1) {        
    $this->_transactionNestingLevel = 0;        
    $this->_conn->rollback();        
    $this->_isRollbackOnly = false;
    } elseif ($this->_nestTransactionsWithSavepoints) {        
    $this->rollbackSavepoint($this->_getNestedTransactionSavePointName());
        --$this->_transactionNestingLevel;
    } else {        
    $this->_isRollbackOnly = true;
        --$this->_transactionNestingLevel;
    }
}
Copier après la connexion

Vous pouvez voir que la méthode de traitement est également très simple Si le niveau est 1, rollback directement, sinon rollback au point de sauvegarde précédent.

Ensuite, continuons à regarder la fonction commit :

publicfunctioncommit(){    
if ($this->_transactionNestingLevel == 0) {        
throw ConnectionException::noActiveTransaction();
    }    if ($this->_isRollbackOnly) {        
    throw ConnectionException::commitFailedRollbackOnly();
    }    if ($this->_transactionNestingLevel == 1) {        
    $this->_conn->commit();
    } elseif ($this->_nestTransactionsWithSavepoints) {        
    $this->releaseSavepoint($this->_getNestedTransactionSavePointName());
    }

    --$this->_transactionNestingLevel;
}
Copier après la connexion

Oubliez ça, expliquons cela sans tracas :)

La solution de Laravel

La méthode de traitement de Laravel est relativement simple et grossière. Regardons d'abord l'opération de création d'une transaction :

publicfunctionbeginTransaction(){
    ++$this->transactions;    if ($this->transactions == 1)
    {        $this->pdo->beginTransaction();
    }
}
Copier après la connexion

Comment vous sentez-vous ? Tellement facile, non ? Déterminez d’abord combien de transactions il y a actuellement. Si c’est la première, ok, la transaction démarre. Sinon, rien n’est fait. Alors pourquoi rien n’est fait ? Continuez à regarder le fonctionnement du rollBack :

publicfunctionrollBack(){    if ($this->transactions == 1)
    {        $this->transactions = 0;        $this->pdo->rollBack();
    }    else
    {
        --$this->transactions;
    }
}
Copier après la connexion

Vous comprenez ? Ce n'est que lorsqu'il n'y a qu'une seule transaction en cours qu'elle sera véritablement annulée, sinon le nombre sera simplement décrémenté d'un. C'est pourquoi je viens de dire que le traitement de Laravel est relativement simple et grossier. Il n'y a en fait aucune transaction réelle dans la couche interne imbriquée. Bien qu'elle soit simple et grossière, elle résout également le problème. of Lorsque la couche interne crée une nouvelle transaction, cela entraînera des problèmes de validation. Le principe est le suivant. Par souci d'exhaustivité, copiez également le code de commit !

publicfunctioncommit(){    
if ($this->transactions == 1) $this->pdo->commit();

    --$this->transactions;
}
Copier après la connexion

Ce qui précède est le contenu de l'implémentation des transactions imbriquées de MySQL. Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois (m.sbmmt.com) !


Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal