Автоматизировать открытие и закрытие соединения с базой данных - PullRequest
0 голосов
/ 25 декабря 2011

Я пишу класс для запросов к базе данных с SQLite3 в моем приложении.Большинство методов класса очень похожи на это:

def getPrice(self, symbol, date):
    date = dt.datetime.strptime(date, '%Y-%m-%d')
    conn = sqlite3.connect('stocks.db')
    curs =conn.cursor()
    curs.execute('''SELECT close FROM prices WHERE symbol = ? AND date = ?;''', (symbol, date))
    close = curs.fetchall()
    curs.close()
    return close

Единственное отличие - это запрос к базе данных и количество аргументов.Есть ли возможность абстрагироваться от открытия и закрытия соединения с базой данных?

Я знаю, что было бы, вероятно, проще использовать ORM, такой как SQLAlchemy.Но я хочу понять, как я решаю эту проблему в целом, а не только в отношении баз данных.

Спасибо за ваши предложения!

РЕДАКТИРОВАТЬ: Этот пост в основномотвечает на мой вопрос.

Ответы [ 3 ]

4 голосов
/ 25 декабря 2011

Во-первых.Вы будете намного, намного счастливее с одной - и только с одной - глобальной связью.Изменения конфигурации намного проще, если вы делаете это в одном месте.

Во-вторых, используйте оператор with и библиотеку менеджера контекста.

from contextlib import closing
from my_database_module import the_global_connection

def getPrice(
    with closing(the_global_connection.cursor())
        curs.execute('''SELECT close FROM prices WHERE symbol = ? AND date = ?;''', (symbol, date))
        close = curs.fetchall()
    return close

Ваш модуль базы данных выглядит следующим образом:

import sqlite3
the_global_connection = sqlite3.connect( "stocks.db" )

Это дает вам возможность изменять базы данных или технологию сервера баз данных в одном месте.

2 голосов
/ 25 декабря 2011

Обратите внимание, что начиная с Python2.6, sqlite.connect возвращает менеджер контекста :

Объекты соединения могут использоваться как контекстные менеджеры, которые автоматически фиксация или откат транзакций. В случае исключения откат транзакции; в противном случае транзакция совершается:

Следовательно, не украшает соединение с contextlib.closing - иначе вы потеряете поведение фиксации / отката и вместо этого получите только connection.close(), вызванный при выходе из with-statement.

За PEP249 :

... closing a connection without committing the changes first will cause
an implicit rollback to be performed.

Таким образом, поведение фиксации / отката гораздо полезнее, чем простой вызов close.


Вы можете использовать менеджер контекста :

import contextlib

def query(sql,args):
    with contextlib.closing(sqlite3.connect('stocks.db')) as conn:
        curs = conn.cursor()
        curs.execute(sql,args))
        close = curs.fetchall()
        return close

def getPrice(self, symbol, date):
    date = dt.datetime.strptime(date, '%Y-%m-%d')
    sql = '''SELECT close FROM prices WHERE symbol = ? AND date = ?'''
    args = (symbol, date)
    return query(sql, args)

Поскольку у вас есть много функций, таких как getPrice, которые отличаются только SQL и аргументами, вы можете уменьшить количество повторяющихся кодов, определив функцию query.

Вы также можете определить менеджер контекста для отката соединения при ошибках и фиксации, а также закрытия при выходе из блока with. Пример этого (для MySQL) можно найти здесь , адаптировать его к sqlite3 не должно быть сложно ..

Справка:

1 голос
/ 25 декабря 2011

Инкапсулируйте эту логику в объект, передайте этот объект объекту доступа к данным и попросите его вызвать методы.

Аспекты или декораторы могут быть хорошим способом сделать что-то.

Вы не упоминаете пул или транзакции. Подумайте и о них.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...