【问题标题】:Using decorators for database access with psycopg2通过 psycopg2 使用装饰器进行数据库访问
【发布时间】:2015-09-12 09:32:57
【问题描述】:

我正在构建一个模型,该模型在 Postgresql 数据库中进行大部分计算(出于性能原因)。它看起来有点像这样:

def sql_func1(conn):
    # prepare some data, crunch some number, etc.
    curs = conn.cursor()
    curs.execute("SOME SQL COMMAND")
    curs.commit()
    curs.close()

if __name__ == "__main__":
    connection = psycopg2.connect(dbname='name', user='user', password='pass', host='localhost', port=1234)
    sql_func1(conn)
    sql_func2(conn)
    sql_func3(conn)
    connection.close()

该脚本使用了大约 30 个单独的函数,例如 sql_func1。显然,一直在每个函数中管理连接和游标有点尴尬。因此,我开始使用 here 描述的装饰器。现在我可以简单地用装饰器@db_connect 包装sql_func1 并从那里传递连接。但是,这意味着我一直在打开和关闭连接,这也不是一个好习惯。 psycopg2 FAQ 说:

创建连接可能会很慢(想想基于 TCP 的 SSL),所以最好 做法是创建单个连接并保持打开状态 必需的。经常回滚或提交也是一个好习惯 (即使在单个 SELECT 语句之后)以确保后端是 从未离开过“闲置交易”。另请参阅 psycopg2.pool 了解 轻量级连接池。

您能否给我一些见解,这将是我的理想实践。我应该使用传递cursor 对象而不是connection 的装饰器吗?如果是这样,请提供装饰器的代码示例。由于我对编程比较陌生,如果您认为我的整体方法有误,请告诉我。

【问题讨论】:

  • 您是否将尽可能多的逻辑转移到 SQL 以减少往返次数?
  • @ClodoaldoNeto 模型需要模块化。因此我使用了一系列较小的函数。我没听错你的问题吗?

标签: python postgresql psycopg2


【解决方案1】:

将连接存储在全局变量中而不在finally 块中关闭它会怎样?像这样的东西(根据你链接的例子):

cnn = None
def with_connection(f):

    def with_connection_(*args, **kwargs):
        global cnn
        if not cnn:
            cnn = psycopg.connect(DSN)
        try:
            rv = f(cnn, *args, **kwargs)
        except Exception, e:
            cnn.rollback()
            raise
        else:
            cnn.commit() # or maybe not        
        return rv

    return with_connection_

【讨论】:

  • 也许我不明白,但这基本上是我在代码示例中所做的,不是吗?会有什么优势?另外我认为您应该在答案中将cnn.close() 添加到exception
  • 基本上是的,但你会使用装饰器(如果尚未建立连接,它会初始化连接)。您不需要关闭except 块中的连接(除非您想在单个查询失败时关闭连接)
  • 好的,谢谢。我的印象是使用装饰器的一大优势是确保连接已关闭。在您看来,使用装饰器传递 cursor 不是一个好主意?
猜你喜欢
  • 2021-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-25
  • 1970-01-01
  • 2017-06-19
  • 2019-04-25
  • 2013-02-03
相关资源
最近更新 更多