【问题标题】:Automate Opening and Closing the Database Connection自动打开和关闭数据库连接
【发布时间】:2011-12-25 16:23:08
【问题描述】:

我正在我的应用程序中使用 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

唯一的区别是数据库查询和参数的数量。是否有可能将数据库连接的打开和关闭抽象掉?

我知道使用像 SQLAlchemy 这样的 ORM 可能会更容易。但我想了解我是如何解决这类问题的,而不仅仅是与数据库相关的问题。

感谢您的建议!

编辑:This post 基本上回答了我的问题。

【问题讨论】:

    标签: python class database-connection


    【解决方案1】:

    首先。拥有一个——而且只有一个——全球连接,你会非常非常高兴。如果您只在一个地方执行此操作,配置更改会容易得多。

    其次,使用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" )
    

    这使您能够在一处更改数据库或数据库服务器技术。

    【讨论】:

    • contextlib 听起来很有希望。我会调查这个。全球连接也是我将实施的一个方面。谢谢。
    • 我还有一个关于全局数据库连接的问题。当我建立自己的数据库类“数据库”时,我必须在每次需要连接时实例化并调用这个类:db = database()conn=db.the_global_connection。有没有更简单的代码更少的方法?或者也许是如何使用不同类的一个很好的例子?抱歉,如果这对你来说是微不足道的,但我刚开始使用 OOP。
    • "并在每次我想要连接时调用此类:db = database()"。我要告诉你一个单一的全局连接object。单个全局连接对象。只创建一个数据库连接实例。
    【解决方案2】:

    注意,从 Python2.6 开始,sqlite.connectreturns a context manager

    连接对象可以用作上下文管理器,自动 提交或回滚事务。发生异常时, 事务回滚;否则,事务被提交:

    因此,不要使用contextlib.closing 装饰连接——否则,您将失去提交/回滚行为,而只会在退出with-statement 时调用connection.close()

    PEP249

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

    所以提交/回滚行为比简单地调用 close 有用得多。


    你可以使用context manager:

    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)可以在here 找到,适应 sqlite3 应该不难..

    参考:

    【讨论】:

    • 虽然这是一种改进,尤其是在资源管理方面,但它并没有比 OP 所呈现的节省太多代码。
    【解决方案3】:

    将该逻辑封装到一个对象中,将该对象传递给数据访问对象并要求它调用方法。

    方面或装饰器可能是做事的好方法。

    您没有提到池化或交易。想想这些。

    【讨论】:

    • 您能解释一下方面的含义吗?我从来没有听说过这个概念。感谢其他想法。
    • 面向方面的编程。在 Python 中,它们被称为装饰器:wiki.python.org/moin/PythonDecorators
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-31
    • 2017-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多