2012-03-21 8 views
12

Supongamos, tengo una declaración de modificación:Python-mysql: cuando a deshacer de manera explícita una transacción

cursor = conn.cursor() 
# some code 
affected_rows1 = cursor.execute(update_statement1, params1) 
# some code 
conn.commit() 
cursor.close() 

¿Debo situar el bloque de código con una try ... except y explícitamente deshacer una transacción cuando se produce una excepción, y qué excepciones de MySQLdb debo tomar para deshacer? Solía ​​detectar StandardError en este caso, pero ahora dudo que el bloque de código necesite una reversión explícita.

El siguiente ejemplo es un poco más difícil, y entiendo que requiere una reversión explícita si la primera declaración de actualización tuvo éxito. Sin embargo, las excepciones que debo coger en este caso:

cursor = conn.cursor() 
# some code 
affected_rows1 = cursor.execute(update_statement1, params1) 
# some code 
affected_rows2 = cursor.execute(update_statement2, params2) 
#some code 
conn.commit() 
cursor.close() 

Respuesta

1

en mi humilde opinión, se debe deshacer transacciones si continúa usando la misma conexión. Todo lo demás antes del error se comprometerá cuando termine las transacciones. Para la excepción de capturar, siempre uso MySQLdb.Error pero no estoy seguro de que sea correcto.

+0

utilizo incluso 'StandardError', y ahora estoy tratando de entender lo que es correcto para estar seguro. – newtover

-1

Se recomienda ajustar execute() en un sub. Así es como lo hago.

def executeSQL(self, stmt): 
    cursor = self.dbHand.cursor() 

    if not stmt.endswith(";"): 
     stmt += ';' 

    try: 
     cursor.execute(stmt) 
    except MySQLdb.Error, e: 
     self.logger.error("Caught MYSQL exception :%s: while executing stmt :%s:.\n"%(e,stmt)) 
     return False 
+1

Entiendo que, mi pregunta es sin embargo acerca de las condiciones para invocar 'rollback' implícito – newtover

+1

¿Puede aclarar el beneficio de este método, por favor? – Dikei

+0

Como @Dikei mencionó rollback() si se atrapa la excepción MySQLdb.Error. – tuxuday

12

This link muestra los distintos tipos de errores que puede detectar. MySQLdb.Error es la clase base estándar de la que se derivan todos los demás errores de MySQL.

Normalmente utilizo MySQLdb.Error porque le permite concentrarse en los errores relacionados con MySQLdb. Por el contrario StandardError capturará casi todas las excepciones (no es algo que desee si desea una mejor capacidad de depuración). Además, el uso de MySQLdb.Error le permite mostrar el mensaje de error exacto (MySQL número de error y todo) para que pueda depurarlo más rápido.

Llegando a la primera parte de la pregunta, en el caso de los enunciados de la base de datos es (por lo general) necesario revertir las transacciones (si son compatibles) en caso de error.

La metodología que sigo es para envolver cada declaración execute en una cláusula try except (catch MySQLdb.Error) y usar rollback si hay un error antes de imprimir el mensaje de error y salir.

Sin embargo, hay una trampa. En MySQLdb, los cambios que realice en la base de datos son no realmente escritos en la base de datos hasta que explícitamente se llame a commit. Entonces, lógicamente, la reversión no es necesaria.

A modo de ejemplo,

conn = MySQLdb.connection(db=, host=, passwd=, user=) 
cur = conn.cursor() 
#Say you have a table X with one entry id = 1 and total = 50 
cur.execute("update X set total = 70 where id = 1") 
#Actual DB has not yet changed 
cur.execute("update X set total = 80 where id = 1") 
#Actual DB has still not changed 

Si sale del programa sin cometer, el valor en el PP seguirá siendo 50 porque nunca se compromete llamada().

Esta es la forma en que lo ideal sería hacerlo:

conn = MySQLdb.connection(db=, host=, passwd=, user=) 
cur = conn.cursor() 
#Say you have a table X with one entry id = 1 and total = 50 
try: 
    cur.execute("update X set total = 70 where id = 1") 
except MySQLdb.Error,e: 
    print e[0], e[1] 
    conn.rollback() 
    cur.close() 
    conn.close() 
    #print lengthy error description!! 
    sys.exit(2) 
    #Note: Value in table is still 50 
#If you do conn.commit() here, value becomes 70 in table too!! 
try: 
    cur.execute("update X set total = 80 where id = 1") 
except MySQLdb.Error,e: 
    print e[0], e[1] 
    conn.rollback() 
    cur.close() 
    conn.close() 
    #print lengthy error description!! 
    sys.exit(2) 
    #Value in DB will be 
    #a) 50 if you didn't commit anywhere 
    #b) 70 if you committed after first execute statement 
conn.commit() 
#Now value in DB is 80!! 
cur.close() 
conn.close() 
+0

Un modelo de respuesta de StackOverflow (explicación + ejemplo de trabajo completo). Magnífico. – Pyderman

+0

Si la confirmación() en sí misma falla de alguna manera, ¿es necesario deshacer() para abandonar los cambios de la ejecución() para que la próxima confirmación() (que no tiene su ejemplo) no los obtenga? – Syncopated

+2

práctica estándar y segura que se debe seguir es: 'try {start transaction; ejecutar declaraciones; commit transaction;} catch (Exception e) {realizar rollback; } finally {cerrar DB resources como declaración; } 'También este punto" _Así que, lógicamente, la reversión no es necesaria._ "si la confirmación no se produce es incorrecta porque la transacción permanecerá abierta y que podría generar problemas graves, como el reinicio de otra transacción implicará implícitamente la anterior que no has cerrado (retrocedido). – sactiw

Cuestiones relacionadas