Как включить автоматическое повторное соединение клиента MySQL с MySQLdb? - PullRequest
35 голосов
/ 16 октября 2008

Я натолкнулся на PHP способ сделать трюк:

my_bool reconnect = 1;
mysql_options(&mysql, MYSQL_OPT_RECONNECT, &reconnect);

но не повезло с MySQLdb (python-mysql).

Может кто-нибудь дать подсказку? Спасибо.

Ответы [ 7 ]

76 голосов
/ 11 июня 2009

Я решил эту проблему, создав функцию, обертывающую метод cursor.execute(), поскольку именно это вызывало исключение MySQLdb.OperationalError. Другой пример выше подразумевает, что это метод conn.cursor(), который вызывает это исключение.

import MySQLdb

class DB:
  conn = None

  def connect(self):
    self.conn = MySQLdb.connect()

  def query(self, sql):
    try:
      cursor = self.conn.cursor()
      cursor.execute(sql)
    except (AttributeError, MySQLdb.OperationalError):
      self.connect()
      cursor = self.conn.cursor()
      cursor.execute(sql)
    return cursor

db = DB()
sql = "SELECT * FROM foo"
cur = db.query(sql)
# wait a long time for the Mysql connection to timeout
cur = db.query(sql)
# still works
15 голосов
/ 29 марта 2015

У меня были проблемы с предложенным решением, потому что оно не уловило исключение. Я не уверен почему.

Я решил проблему с оператором ping(True), который мне кажется более аккуратным:

import MySQLdb
con=MySQLdb.Connect()
con.ping(True)
cur=con.cursor()

Понял отсюда: http://www.neotitans.com/resources/python/mysql-python-connection-error-2006.html

10 голосов
/ 17 октября 2008

Если вы используете Ubuntu Linux, в пакет python-mysql был добавлен патч, в котором добавлена ​​возможность установить ту же опцию MYSQL_OPT_RECONNECT (см. здесь ). Я не пробовал это все же.

К сожалению, патч был позже удален из-за конфликта с автоподключением и переходами (описано здесь ).

Комментарии на этой странице говорят: 1.2.2-7 Опубликовано в intrepid-выпуске 2008-06-19

python-mysqldb (1.2.2-7) нестабильный; срочность = низкий

[Сандро Тоси] * debian / control - строки списка элементов в описании начинаются с 2 пробелов, чтобы избежать переформатирования на веб-страницах (закрытие: # 480341)

[Бернд Зеймец] * debian / patches / 02_reconnect.dpatch: - Удаление патча: Комментарий в Storm, который объясняет проблему:

    # Here is another sad story about bad transactional behavior. MySQL
    # offers a feature to automatically reconnect dropped connections.
    # What sounds like a dream, is actually a nightmare for anyone who
    # is dealing with transactions. When a reconnection happens, the
    # currently running transaction is transparently rolled back, and
    # everything that was being done is lost, without notice. Not only
    # that, but the connection may be put back in AUTOCOMMIT mode, even
    # when that's not the default MySQLdb behavior. The MySQL developers
    # quickly understood that this is a terrible idea, and removed the
    # behavior in MySQL 5.0.3. Unfortunately, Debian and Ubuntu still
    # have a patch right now which *reenables* that behavior by default
    # even past version 5.0.3.
3 голосов
/ 05 ноября 2010

вы можете разделить коммит и закрытие для соединения ... это не мило, но оно делает это.

class SqlManager(object):
 """
 Class that handle the database operation
 """
 def __init__(self,server, database, username, pswd):

      self.server = server
      self.dataBase = database
      self.userID = username
      self.password = pswd

def Close_Transation(self):
      """
      Commit the SQL Query
      """
      try:
        self.conn.commit()
      except Sql.Error, e:
        print "-- reading SQL Error %d: %s" % (e.args[0], e.args[1])

 def Close_db(self):
    try:
        self.conn.close()
    except Sql.Error, e:
        print "-- reading SQL Error %d: %s" % (e.args[0], e.args[1])

 def __del__(self):
    print "close connection with database.."
    self.conn.close() 
1 голос
/ 06 июля 2018

Мне нужно решение, которое работает аналогично решению Гаррета, но для cursor.execute(), поскольку я хочу, чтобы MySQLdb выполнял все побеги для меня. Модуль оболочки в итоге выглядел так (использование ниже):

#!/usr/bin/env python

import MySQLdb

class DisconnectSafeCursor(object):
    db = None
    cursor = None

    def __init__(self, db, cursor):
        self.db = db
        self.cursor = cursor

    def close(self):
        self.cursor.close()

    def execute(self, *args, **kwargs):
        try:
            return self.cursor.execute(*args, **kwargs)
        except MySQLdb.OperationalError:
            self.db.reconnect()
            self.cursor = self.db.cursor()
            return self.cursor.execute(*args, **kwargs)

    def fetchone(self):
        return self.cursor.fetchone()

    def fetchall(self):
        return self.cursor.fetchall()

class DisconnectSafeConnection(object):
    connect_args = None
    connect_kwargs = None
    conn = None

    def __init__(self, *args, **kwargs):
        self.connect_args = args
        self.connect_kwargs = kwargs
        self.reconnect()

    def reconnect(self):
        self.conn = MySQLdb.connect(*self.connect_args, **self.connect_kwargs)

    def cursor(self, *args, **kwargs):
        cur = self.conn.cursor(*args, **kwargs)
        return DisconnectSafeCursor(self, cur)

    def commit(self):
        self.conn.commit()

    def rollback(self):
        self.conn.rollback()

disconnectSafeConnect = DisconnectSafeConnection

Использование этого тривиально, отличается только начальное соединение. Расширьте классы методами-обертками в соответствии с вашими потребностями в MySQLdb.

import mydb

db = mydb.disconnectSafeConnect()
# ... use as a regular MySQLdb.connections.Connection object

cursor = db.cursor()

# no more "2006: MySQL server has gone away" exceptions now
cursor.execute("SELECT * FROM foo WHERE bar=%s", ("baz",))
1 голос
/ 17 октября 2008

У меня была похожая проблема с MySQL и Python, и решение, которое работало для меня, состояло в том, чтобы обновить MySQL до 5.0.27 (в Fedora Core 6; ваша система может нормально работать с другой версией).

Я пробовал много других вещей, включая исправление библиотек Python, но обновление базы данных было намного проще и (я думаю) лучшим решением.

0 голосов
/ 17 октября 2008

Вы делаете ставку на то, чтобы обойти прерванные соединения самостоятельно с помощью кода.

Один из способов сделать это будет следующим:

import MySQLdb

class DB:
    conn = None

    def connect(self):
        self.conn = MySQLdb.connect()

    def cursor(self):
        try:
            return self.conn.cursor()
        except (AttributeError, MySQLdb.OperationalError):
            self.connect()
            return self.conn.cursor()

db = DB()
cur = db.cursor()
# wait a long time for the Mysql connection to timeout
cur = db.cursor()
# still works
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...