Maison  >  Article  >  développement back-end  >  Comment implémenter des transactions imbriquées MySQL en PHP

Comment implémenter des transactions imbriquées MySQL en PHP

不言
不言original
2018-06-13 15:09:551809parcourir

Cet article présente principalement deux solutions pour implémenter des transactions imbriquées MySQL en PHP. Cet article analyse les méthodes d'implémentation de doctrine et de laravel, et les extrait pour analyse et résumé.

<.>1. Origine du problème

Dans la documentation officielle de MySQL, il est clairement indiqué que les transactions imbriquées ne sont pas supportées :

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.
Mais quand on développe un complexe SystèmeIl est inévitable que les transactions soient imbriquées involontairement dans les transactions.Par exemple, la fonction A appelle la fonction B, la fonction A utilise une transaction et appelle la fonction B dans 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 ? Il est mentionné dans le document ci-dessus. Une traduction simple est :

当执行一个START TRANSACTION指令时,会隐式的执行一个commit操作。
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 une transaction dans Doctrine (code non pertinent tué). ):

public function beginTransaction()
{
    ++$this->_transactionNestingLevel;
    if ($this->_transactionNestingLevel == 1) {
        $this->_conn->beginTransaction();
    } else if ($this->_nestTransactionsWithSavepoints) {
        $this->createSavepoint($this->_getNestedTransactionSavePointName());
    }
}
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 Exécuter START TRANSACTION et. tout ira bien. S'il est supérieur à 1, c'est-à-dire lorsqu'il y a une 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 :

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;
    }
}
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 :

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;
}
Oubliez ça, expliquons cela sans tracas :)

La solution de Laravel Solution 3.

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

public function beginTransaction()
{
    ++$this->transactions;
    if ($this->transactions == 1)
    {
        $this->pdo->beginTransaction();
    }
}
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 :

public function rollBack()
{
    if ($this->transactions == 1)
    {
        $this->transactions = 0;
        $this->pdo->rollBack();
    }
    else
    {
        --$this->transactions;
    }
}
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é, veuillez copier le code de commit !

public function commit()
{
    if ($this->transactions == 1) $this->pdo->commit();
    --$this->transactions;
}
Ce qui précède représente l'intégralité du contenu de cet article. J'espère qu'il sera utile à l'étude de chacun. Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois !


Recommandations associées :

Comment utiliser la fonction mb_detect_encoding en PHP

Comment utiliser le support de l'envoi smtp en php Courriel ci-joint

Comment implémenter le processus asynchrone d'exécution du superviseur dans le framework Laravel en PHP

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
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