Синхронизация исключений курсора базы данных Python - PullRequest
1 голос
/ 02 июня 2011

Я создаю класс, который будет управлять подключением к базе данных Firebird.Служба 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 Database API, и если да, то как они были преодолены?

Ответы [ 2 ]

1 голос
/ 15 июня 2011

Я тестирую следующие модификации в своем классе, которые, я считаю, достигнут централизованной обработки, которую я хочу, с минимальным дублированием кода. Они также немного упрощают методы query и 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
0 голосов
/ 14 июня 2011

Соединение БД с Firebird испытывает проблемы с обнаружением соединения как стандартные соединения TCP / IP.То есть соединение не может быть легко обнаружено как «мертвое», пока оно не используется.Чтобы обойти это в мире TCP / IP, можно использовать KeepAlives (все еще ~ 15 минутный цикл обнаружения) и явные тактовые импульсы.Отправка запроса на обнаружение аналогична отправке контрольного сигнала, чтобы убедиться, что он все еще жив.

Когда вы выполняете оператор SQL для курсора, вы получите исключение в тот момент, когда он отключен.Подходящее место для обнаружения сбоя подключения находится в точке использования.Централизованная проверка ошибок - отличная цель, но, реализованная, как указано выше, вы все еще оставляете открытой возможность потери соединения с Firebird между возвратом действительного объекта курсора и последующим выполнением (то есть вы все равно можете потерпеть неудачу при вызове execute () в dml () функция).

...