Gestor de contexto para MySQLdb de Python

Estoy acostumbrado a (¿estropeado por?) La interfaz SQLite de Python para tratar con bases de datos SQL. Una buena característica de la API SQLite de python es el “administrador de contexto”, es decir, python’s with statement. Normalmente ejecuto consultas de la siguiente manera:

 import as sqlite with sqlite.connect(db_filename) as conn: query = "INSERT OR IGNORE INTO shapes VALUES (?,?);" results = conn.execute(query, ("ID1","triangle")) 

Con el código anterior, si mi consulta modifica la base de datos y me olvido de ejecutar conn.commit() , el administrador de contexto lo ejecuta automáticamente al salir de la instrucción with . También maneja muy bien las excepciones: si se produce una excepción antes de que confirme algo, la base de datos se retrotrae.

Ahora estoy usando la interfaz MySQLdb , que parece no ser compatible con un administrador de contexto similar. ¿Cómo creo mi propio? Aquí hay una pregunta relacionada, pero no ofrece una solución completa.

Anteriormente , las conexiones de MySQLdb eran gestores de contexto. Sin embargo, a partir de esta confirmación en 2018-12-04 , las conexiones MySQLdb ya no son administradores de contexto, y los usuarios deben llamar explícitamente a conn.commit () o conn.rollback (), o escribir su propio administrador de contexto, como el que se encuentra a continuación. .


Podrías usar algo como esto:

 import config import MySQLdb import MySQLdb.cursors as mc import _mysql_exceptions import contextlib DictCursor = mc.DictCursor SSCursor = mc.SSCursor SSDictCursor = mc.SSDictCursor Cursor = mc.Cursor @contextlib.contextmanager def connection(cursorclass=Cursor, host=config.HOST, user=config.USER, passwd=config.PASS, dbname=config.MYDB, driver=MySQLdb): connection = driver.connect( host=host, user=user, passwd=passwd, db=dbname, cursorclass=cursorclass) try: yield connection except Exception: connection.rollback() raise else: connection.commit() finally: connection.close() @contextlib.contextmanager def cursor(cursorclass=Cursor, host=config.HOST, user=config.USER, passwd=config.PASS, dbname=config.MYDB): with connection(cursorclass, host, user, passwd, dbname) as conn: cursor = conn.cursor() try: yield cursor finally: cursor.close() with cursor(SSDictCursor) as cur: print(cur) connection = cur.connection print(connection) sql = 'select * from table' cur.execute(sql) for row in cur: print(row) 

Para usarlo, debe poner config.py en su PYTHONPATH y definir las variables HOST, USER, PASS, MYDB allí.

Piensa que las cosas han cambiado desde que esta pregunta fue formulada originalmente. Algo confuso (al menos desde mi punto de vista), para las versiones recientes de MySQLdb , si usa una conexión en un contexto, obtiene un cursor (según el ejemplo de oursql ), no algo que se cierre automáticamente (como lo haría si abriera un archivo por ejemplo).

Esto es lo que hago:

 from contextlib import closing with closing(getConnection()) as conn: #ensure that the connection is closed with conn as cursor: #cursor will now auto-commit cursor.execute('SELECT * FROM tablename')