Curso manejo de bases de datos con Python

Autor: Luis Fernando Apáez Álvarez

Clase 4: Manejo de transacciones

Básicamente, una transacción es una secuencia de trabajo realizado de forma ordenada y separada en una BD. Normalmente representan cualquier cambio en la base de datos. Dentro de una transacción ejecutaremos todas las instrucciones o no ejecutaremos ninguna.

En caso de que todas las instrucciones hayan sido ejecutadas de forma exitosa, entonces los cambios serán guardados por lo que haremos commit de la transacción y así concluiremos que la transacción ha sido exitosa.

Si no son ejecutadas las instrucciones, es decir que alguna de ellas falló, entonces haremos rollback, es decir, dar marcha atrás en todos los posibles cambios que se generaron en las BD. Lo anterior indica que la transacción ha fallado.

Para ejemplificar lo anterior escribamos primero el código para realizar una inserción:

try:
    cursor = conexion.cursor() 
    query = 'INSERT INTO curso_python VALUES(%s, %s, %s, %s)'
    values = ('Eugenia', 'López', 20, 'CDMX')
    cursor.execute(query, values)
    print("Inserción exitosa")
except Exception as e:
    print(f'Ocurrio un error: {e}')

Ahora, por default tenemos que conexion.autocommit=False lo que quiere decir que no guardamos cambio de manera automática. De hecho, conexion.autocommit=True que hace que los cambios se guarden de manera automática no es una buena práctica. Ahora bien, puede decirse que la sentencia almacenada en query representa un cambio en la BD, así, para crear una transacción debemos de aplicar un commit para el caso enq ue dicha sentencia se ha ejecutado exitosamente, y un rollback en el caso en que ésta no se haya ejecutado exitosamente. Para ello agregamos

try:
    cursor = conexion.cursor() 
    query = 'INSERT INTO curso_python VALUES(%s, %s, %s, %s)'
    values = ('Eugenia', 'López', 20, 'CDMX')
    cursor.execute(query, values)

    # guardamos los cambios
    conexion.commit()
    print("Inserción exitosa")

except Exception as e:

    # hacemos un rollback
    conexion.rollback()
    print(f'Ocurrio un error: {e}')
finally:
    conexion.close()

El código anterior representa una transacción. Podríamos agregar más sentencias a la transacción

try:
    cursor = conexion.cursor() 
    query = 'INSERT INTO curso_python VALUES(%s, %s, %s, %s)'
    values = ('Eugenia', 'López', 20, 'CDMX')
    cursor.execute(query, values)

    query = 'UPDATE curso_python SET nombre = %s WHERE id_curso=3'
    values = ('Denis',)
    cursor.execute(query, values)

    # guardamos los cambios
    conexion.commit()
    print("Transacción exitosa")

except Exception as e:

    # hacemos un rollback
    conexion.rollback()
    print(f'Ocurrio un error: {e}')
finally:
    conexion.close()

No obstante, utilizar administradores de contexto como lo hicimos en las clases pasadas es lo más adecuado y recomendable para trabajar con las transacciones pues, de manera automática, el administrador de contexto se encarga de realizar el commit cuando las instrucciones se han ejecutado exitosamente; si éstas no se ejecutaron, de manera automática se hará el rollback.

Por ende, el código final quedaría como

try:
    with conexion:
            with conexion.cursor() as cursor:
                cursor = conexion.cursor() 
                query = 'INSERT INTO curso_python VALUES(%s, %s, %s, %s)'
                values = ('Eugenia', 'López', 20, 'CDMX')
                cursor.execute(query, values)

                query = 'UPDATE curso_python SET nombre = %s WHERE id_curso=3'
                values = ('Denis',)
                cursor.execute(query, values)

                print("Transacción exitosa")

except Exception as e:
    print(f'Ocurrio un error: {e}')

finally:
    conexion.close()

donde quitamos del código conexion.commit() y conexion.rollback pues sus funciones son realizadas de forma automática por los administradores de contexto.