2010-02-25 8 views
6

Je veux savoir si l'ouverture d'une transaction dans un autre est sûre et encouragée?Transaction dans la transaction

J'ai une méthode:

def foo(): 
    session.begin 
    try: 
      stuffs 
    except Exception, e: 
     session.rollback() 
     raise e 
    session.commit() 

et une méthode qui appelle la première, dans une transaction:

def bar(): 
    stuffs 
    try: 
     foo() #<<<< there it is :) 
     stuffs 
    except Exception, e: 
     session.rollback() 
     raise e 
    session.commit() 

si je reçois et exception sur la méthode foo, toutes les opérations seront être annulé? et tout le reste fonctionnera bien? merci !!

+1

Les transactions imbriquées (par exemple AUTONOMOUS_TRANSACTION d'Oracle) sont considérées comme un anti-pattern hormis deux cas: Audit (la tentative est auditée même si l'instruction est annulée) et Error Logging (pour capturer où/quand des échecs existent). Tous les autres cas doivent utiliser des points de sauvegarde. Heck, la portée de la transaction n'appartient à aucune fonction ou procédure; Ce devrait être la responsabilité ultime de l'appelant de s'engager ou de revenir en arrière. –

+0

C'est une transception. – user

Répondre

15

Il existe deux façons d'imbriquer des transactions dans SQLAlchemy. L'un est les transactions virtuelles, où SQLAlchemy garde la trace du nombre de début que vous avez émis et émet la validation uniquement lorsque la transaction la plus externe est validée. La restauration est toutefois émise immédiatement. Comme la transaction est virtuelle, c'est-à-dire que la base de données ne connaît rien de l'imbrication, vous ne pouvez rien faire avec cette session après l'annulation jusqu'à ce que vous annuliez toutes les transactions externes. Pour autoriser l'utilisation des transactions virtuelles, ajoutez l'argument subtransactions=True à l'appel begin(). Cette fonctionnalité existe pour vous permettre d'utiliser le contrôle des transactions dans des fonctions qui pourraient s'appeler sans suivre si vous êtes dans une transaction ou non. Pour que cela ait du sens, configurez la session avec autocommit=True et émettez toujours un session.begin(subtransactions=True) dans une fonction transactionnelle.

L'autre manière d'imbriquer des transactions consiste à utiliser des transactions réelles imbriquées. Ils sont implémentés en utilisant des points de sauvegarde. Si vous annulez une transaction imbriquée, toutes les modifications effectuées au sein de cette transaction sont annulées, mais la transaction externe reste utilisable et toutes les modifications apportées par la transaction externe sont toujours présentes. Pour utiliser le numéro de transaction imbriqué session.begin(nested=True) ou simplement session.begin_nested(). Les transactions imbriquées ne sont pas prises en charge pour toutes les bases de données. La fonction de configuration de la bibliothèque de suite de tests de SQLAlchemy sqlalchemy.test.requires.savepoints dit ceci au sujet du support:

emits_warning_on('mssql', 'Savepoint support in mssql is experimental and may lead to data loss.'), 
    no_support('access', 'not supported by database'), 
    no_support('sqlite', 'not supported by database'), 
    no_support('sybase', 'FIXME: guessing, needs confirmation'), 
    exclude('mysql', '<', (5, 0, 3), 'not supported by database') 

sur les transactions imbriquées PostgreSQL sqlalchemy fonctionnent très bien.

0

Vous ne pouvez pas, PostgreSQL ne supporte pas les sous-transactions. Vous pouvez utiliser des points de sauvegarde, mais c'est autre chose.

+0

ok. Mais j'exécute le code ci-dessus et sqlalchemy me permet de le faire. que se passe-t-il derrière le rideau? – bluefoot

+0

Je n'ai aucune expérience avec SQLAlchemy quoi que ce soit jamais, ne peut pas vous aider là-bas. Mais je sais que PostgreSQL ne peut pas faire de sous-transactions, Oracle est l'une des rares bases de données à pouvoir faire ce tour. Voir le manuel http://www.sqlalchemy.org/docs/session.html#managing-transactions comment sqlalchemy effectue des transactions et des points de sauvegarde. Et tester, tester, tester! Ne faites pas confiance à votre ORM quand il semble que cela vous permette de faire des choses que votre base de données ne peut pas faire ... –

+0

Lien mis à jour: http://docs.sqlalchemy.org/fr/rel_1_0/orm/session_transaction.html#managing -transactions – Kate

0

Sur PostgreSQL, les transactions imbriquées fonctionnent très bien.

Eh bien, vous n'obtiendrez pas d'erreur (juste un avertissement), c'est vrai. Mais vous ne pouvez pas valider la transaction interne et annuler la transaction externe, la transaction externe annulera également la transaction interne.

BEGIN;

INSÉRER DANS DES VALEURS x (foo) ('John');

BEGIN; -- ATTENTION!

INSÉRER DANS VALEURS y (bar) ('Jane');

COMMIT; - validation de la transaction interne

ROLLBACK; - annulera les deux insertions, pas seulement la première, celle de la table "x"

A ma connaissance, Oracle est l'un des rares qui a cette option.

+3

Transactions postgresql non imbriquées. Transactions SQLAlchemy imbriquées. La transaction interne génère une paire SAVEPOINT et RELEASE SAVEPOINT/ROLLBACK TO SAVEPOINT. Cela entraîne un comportement que l'on pourrait attendre des transactions imbriquées. Il est également implémenté avec SAVEPOINTs sur le backend Oracle. J'ai clarifié la réponse en conséquence. –

Questions connexes