2010-02-25 23 views
6

Quiero saber si abrir una transacción dentro de otra es seguro y alentado?Transacción dentro de la transacción

que tienen un método:

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

y un método que llama a la primera, dentro de una transacción:

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

si consigo y la excepción en el método foo, todas las operaciones se ser rodado hacia atrás? y todo lo demás funcionará bien? gracias !!

+1

Las transacciones anidadas (por ejemplo, AUTONOMOUS_TRANSACTION de Oracle) califican como un antipatrón aparte de dos casos: Auditoría (para que el intento sea auditado incluso si la declaración retrocede) y Registro de errores (para capturar dónde/cuándo existen fallas). Todos los demás casos deben usar savepoints. Diablos, el alcance de la transacción no pertenece a ninguna función o procedimiento; debe ser la responsabilidad final del que llama para comprometerse o deshacerse. –

+0

Eso es transcepción. – user

Respuesta

15

Hay dos formas de anidar transacciones en SQLAlchemy. Una es las transacciones virtuales, donde SQLAlchemy realiza un seguimiento de cuántos inicios ha emitido y emite la confirmación solo cuando la transacción más externa se compromete. Sin embargo, la reversión se emite de inmediato. Como la transacción es virtual, es decir, la base de datos no sabe nada sobre el anidamiento, no puede hacer nada con esa sesión después de la reversión hasta que también restituya todas las transacciones externas. Para permitir el uso de transacciones virtuales, agregue el argumento subtransactions=True a la llamada begin(). Esta característica existe para permitirle usar control de transacciones dentro de funciones que pueden llamarse entre sí sin hacer un seguimiento si está dentro de una transacción o no. Para que tenga sentido, configure la sesión con autocommit=True y siempre emita un session.begin(subtransactions=True) en una función transaccional.

La otra forma de anidar transacciones es usar transacciones anidadas reales. Se implementan usando savepoints. Si restituye una transacción anidada, todos los cambios realizados dentro de esa transacción se retrotraen, pero la transacción externa permanece utilizable y los cambios realizados por la transacción externa continúan allí. Para usar el problema de transacción anidada session.begin(nested=True) o simplemente session.begin_nested(). Las transacciones anidadas no son compatibles con todas las bases de datos. función de configuración de la biblioteca conjunto de pruebas de SQLAlchemy sqlalchemy.test.requires.savepoints dice esto acerca de la ayuda:

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') 

En transacciones anidadas PostgreSQL SQLAlchemy funcionar bien.

0

No se puede, PostgreSQL no admite subtransacciones. Es posible que desee utilizar puntos de rescate, pero eso es algo más.

+0

bien. Pero ejecuto el código anterior y sqlalchemy me permite hacerlo. ¿Qué pasa detrás de la cortina? – bluefoot

+0

No tengo experiencia con SQLAlchemy, lo que nunca, no puedo ayudarte. Pero sí sé que PostgreSQL no puede hacer subtransacciones, Oracle es una de las pocas bases de datos que pueden hacer este truco. Consulte el manual http://www.sqlalchemy.org/docs/session.html#managing-transactions cómo sqlalchemy hace transacciones y puntos de guardado. Y prueba, prueba, prueba! No confíe en su ORM cuando parezca que le permite hacer cosas que su base de datos no puede hacer ... –

+0

Enlace actualizado: http://docs.sqlalchemy.org/en/rel_1_0/orm/session_transaction.html#managing -transacciones – Kate

0

Las transacciones anuladas de PostgreSQL funcionan muy bien.

Bueno, no vas a obtener un error (solo una advertencia), eso es cierto. Pero no puede comprometer la transacción interna y deshacer la transacción externa, la transacción externa también revertirá la transacción interna.

BEGIN;

INSERT INTO x (foo) VALUES ('John');

BEGIN; -- ¡ADVERTENCIA!

INSERT INTO y (bar) VALUES ('Jane');

COMMIT; - commit internal transaction

ROLLBACK; - Revertir ambas inserciones, no solo la primera, la de la tabla "x"

Que yo sepa, Oracle es uno de los pocos que tiene esta opción.

+3

Transacciones postgresql no anidadas. Transacciones anidadas de SQLAlchemy. La transacción interna da como resultado un par SAVEPOINT y RELEASE SAVEPOINT/ROLLBACK TO SAVEPOINT. Esto da como resultado un comportamiento que uno esperaría de las transacciones anidadas. En realidad, también está implementado con SAVEPOINTs en Oracle backend. Aclaré la respuesta en consecuencia. –

Cuestiones relacionadas