Подтвердить что ты не робот

Контекстный менеджер для Python MySQLdb

Я привык (испорчен?) python SQLite интерфейс для работы с базами данных SQL. Одна из приятных особенностей в API-интерфейсе python SQLite - "менеджер контекста", т.е. Оператор python with. Я обычно выполняю запросы следующим образом:

import as sqlite

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

С приведенным выше кодом, если мой запрос изменяет базу данных, и я забыл запустить conn.commit(), менеджер контекста запускает его для меня автоматически после выхода из оператора with. Он также отлично справляется с исключениями: если возникает исключение, прежде чем я что-то совершу, база данных будет отброшена.

Теперь я использую интерфейс MySQLdb, который, похоже, не поддерживает аналогичный менеджер контекста из коробки. Как мне создать свою собственную? Существует связанный с этим вопрос здесь, но он не предлагает полного решения.

4b9b3361

Ответ 1

Раньше соединения MySQLdb были контекстными менеджерами. Однако, начиная с этой фиксации 2018-12-04, соединения MySQLdb больше не являются менеджерами контекста, и пользователи должны явно вызывать conn.commit() или conn.rollback() или писать свой собственный менеджер контекста, такой как приведенный ниже.,


Вы можете использовать что-то вроде этого:

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)

Чтобы использовать его, вы должны поместить config.py в вашу PYTHONPATH и определить там переменные HOST, USER, PASS, MYDB.

Ответ 2

Подумайте, что вещи изменились, поскольку этот вопрос изначально был задан. Несколько пугающе (с моей точки зрения, по крайней мере), для последних версий MySQLdb, если вы используете соединение в контексте, вы получаете курсор (согласно примеру oursql), а не то, что закрывается автоматически (так как вы если бы вы открыли файл, например).

Вот что я делаю:

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