Python数据库游标异常计时



我正在创建一个类,该类将管理与Firebird数据库的连接。将安装火鸟服务,以方便多次连接数据库。不幸的是,我的软件将要部署的环境可能很不稳定,我不能总是保证当我尝试连接时Firebird服务会运行,或者在我建立连接后它会继续运行。

为了集中错误处理,我决定代码的不同部分无论如何都不会直接使用数据库游标。相反,我将从连接管理器中公开query()dml()方法。考虑到下面的代码(为了简洁起见,没有包括一些代码),这在一定程度上是有效的。

class DBConnection(object):
  # self._conn is an instance of kinterbasdb.connect()
  def query(self, query, params = None):
    cursor = self._conn.cursor()
    if params:
      cursor.execute(query, params)
    else:
      cursor.execute(query)
    return [[x[0].title() for x in cursor.description]] + [r for r in cursor.fetchall()]
  def dml(self, query, params = None):
    cursor = self._conn.cursor()
    if params:
      cursor.execute(query, params)
    else:
      cursor.execute(query)
    self._conn.commit()

当Firebird服务停止或由于某种原因无法访问时,故障就会显现出来。我预计self._conn.cursor()会抛出一个异常,这将使做这样的事情变得简单:

class DBConnection(object):
  # self._conn is an instance of kinterbasdb.connect()
  def cursor(self):
    try:
      return self._conn.cursor()
    except:
      # Error handling code here, possibly reconnect, display alert.
  def query(self, query, params = None):
    cursor = self.cursor()
  def dml(self, query, params = None):
    cursor = self.cursor()

不幸的是,当我请求一个游标时,并没有抛出异常。直到接到cursor.execute()的电话,我才意识到问题。这意味着,如果我想正确地集中我的错误处理,我必须做这样的事情:

class DBConnection(object):
  # self._conn is an instance of kinterbasdb.connect()
  def cursor(self):
    try:
      cursor = self._conn.cursor()
      cursor.execute("Select NULL From <sometable>")
      return cursor
    except:
      # Error handling code here, possibly reconnect, display alert.

这需要额外往返于我的数据库,浪费了一个事务(Firebird数据库对数据库生命周期内的总事务有严格的上限),而且通常感觉是错误的。我想知道,有没有人在Python数据库API的其他实现中遇到过类似的情况?如果是,他们是如何克服的?

我正在测试对我的类的以下修改,我相信这些修改将以最小的代码重复实现我想要的集中处理。它们还稍微简化了查询和dml方法,并消除了我想要避免的额外查询(心跳)。

class DBConnection(object):
  # self._conn is an instance of kinterbasdb.connect()
  def query(self, query, params = None):
    cursor = self._conn.cursor()
    self.execute(cursor, query, params)
    return [[x[0].title() for x in cursor.description]] + 
            [r for r in cursor.fetchall()]
  def dml(self, query, params = None):
    cursor = self._conn.cursor()
    self.execute(cursor, query, params)
    self._conn.commit()
  def execute(self, cursor, query, params = None):
    try:
      if params:
        cursor.execute(query, params)
      else:
        cursor.execute(query)
    except Exception, e:
      # Handling

与Firebird的DB连接与标准TCP/IP连接一样存在连接检测问题。也就是说,在使用之前,连接不容易被检测为"死"。在TCP/IP世界中,解决这一问题的方法是使用KeepAlives(仍然是大约15分钟的检测周期)和明确的心跳。发送查询以进行检测类似于发出心跳以查看它是否还活着。

在游标上执行SQL语句时,断开连接时会出现异常。检测连接故障的适当位置是在使用点。集中的错误检查是一个很好的目标,但如上所述,在返回有效的游标对象和稍后的执行之间,您仍然可以保留与Firebird的连接丢失的可能性(即,您仍然可能在dml()函数中的execute()调用失败)。

相关内容

  • 没有找到相关文章

最新更新