【问题标题】:sqlite3.ProgrammingError: Cannot operate on a closed database. [Python] [sqlite]sqlite3.ProgrammingError:无法对关闭的数据库进行操作。 [Python] [sqlite]
【发布时间】:2014-04-13 17:21:07
【问题描述】:

我正在使用一个通用函数来执行一个类中的所有 sqlite 查询。一切正常,直到我在列表中使用包含多个项目的 for 循环。

下面是执行 sqlite 查询的常用函数:

def executeQuery(self, query, params = ()):
        results = {}
        try:
            cur = self.conn.cursor()
            cur.execute(query, params)
            self.conn.commit()
            rows = cur.fetchall()

            results['status'] = 'success'
            result = []
            if rows:
                column = map(lambda x: x[0], cur.description)
                for row in rows:
                    result.append( dict(zip(column, row)) )

            results['results'] = result

        except self.conn.Error, e:
            if self.conn:
                self.conn.rollback()

            print "Error: %s" % e.args[0]
            results['status'] = 'failure'
            results['results'] = e.args[0]

        finally:
            if self.conn:
                self.conn.close()

        return results

这是导致数据库关闭错误的循环:

stages = self.getStageByDate(2000)
        for stage in stages['results']:
            print stage['name']
            additives = self.getStageAdditives(stage['name'])
            print additives
            for additive in additives['results']:
                print additive

错误似乎源自 getStageAdditives(),因为它返回 4 个项目,而 getStageByDate() 仅返回 1 个。

在我看来,在尝试第二次连接之前,与数据库的连接并未关闭。为什么会这样?与 MySQL 数据库一起使用时不会发生这种情况。这个问题有什么解决办法?

【问题讨论】:

    标签: python sql python-2.7 sqlite


    【解决方案1】:

    您写“在我看来,在尝试第二次连接之前与数据库的连接没有关闭”,但实际上,没有与数据库的“第二次连接”。您正在使用单个连接,我猜它是在包含方法 execute_query 的 not-shown-in-your-example 类的初始化程序 (__init__) 中创建的。

    您(再次猜测)在 __init__ 方法中创建了 conn,但在执行任何查询后立即关闭它。因此,当您执行另一个查询时,它将不可用。

    相反,您不应该在查询结束时使用.close(),而应使用.commit()。不要在finally 中执行此操作,而是在try 末尾执行此操作。这样事务将被提交(如果成功)或回滚(在 except 块中,如果失败)。

    然后,将一个单独的 .close() 方法添加到您的较大类中,该方法反过来在连接上调用 .close(),并让调用程序在完成所有查询后调用 that 方法。关闭调用将适当地出现在较大程序内的 finally 块中。

    【讨论】:

    • 啊,这完全是偶然,它以前没有引起问题。整个班级都有一个连接好吗,或者我应该在 executeQuery() 中打开/关闭连接?连接是在与我发布的代码相同的类的 init 中创建的。 try 中已经有一个提交,我认为它不应该在最后,因为如果查询失败,则没有继续处理数据的意义。
    • 这取决于您打算保留该类多长时间以及您是否正在执行任何类型的线程。您为该类创建的对象将不是线程安全的,每个线程都需要它自己的连接。但是,如果您没有使用线程并且小心地在完成对象时始终关闭它,那么它会发现在对象的整个生命周期内都有一个连接(实际上,我就是这样做的)。
    • 是的,我确实错过了提交声明。
    • 我会有一些线程,但它会调用这个类的方法,这会导致问题吗?每次创建新连接都会导致问题(性能不是大问题)吗?
    • 如果对象的__init__ 方法创建了connection,并且每个线程都创建了自己的对象实例,那么您将是安全的。
    【解决方案2】:

    为什么业务方法会关闭连接?当然它应该关闭光标吗?关闭连接意味着第二次调用executeQuery 时会因为连接消失而失败。

    【讨论】:

    • 不确定您所说的业务方法是什么意思,但其余的都是有道理的。您能否发布一个快速示例以确保清晰?
    • @DominicM 在这种情况下,executeQuery 是“业务方法”。不,我不能;我不太了解 Python,无法编写一个很好的示例。 (我确实知道 SQLite API,但主要是其他语言。)
    • 您在正确的轨道上,但不,您无法关闭游标,因为游标没有 close() 方法。我只需要完全删除 conn.close()。
    【解决方案3】:

    从代码中删除它

     self.conn.close()
    

    它会解决问题,因为当你想从数据库中检索信息时你不能写

    conn.close()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-12-25
      • 1970-01-01
      • 2019-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多