如何启用MySQL客户端自动重新连接MySQLdb?

时间:2008-10-16 09:56:06

标签: python mysql

我遇到了PHP的做法:

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

但没有运气MySQLdb(python-mysql)。

任何人都可以提供线索吗?感谢。

8 个答案:

答案 0 :(得分:76)

我通过创建一个包装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

答案 1 :(得分:15)

我对提议的解决方案有疑问,因为它没有捕获异常。我不知道为什么。

我已经用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

答案 2 :(得分:10)

如果您使用的是ubuntu Linux,则会在python-mysql包中添加一个补丁,该补丁添加了设置相同MYSQL_OPT_RECONNECT选项的功能(请参阅here)。我没试过。

不幸的是,由于与自动连接和转换的冲突,后来删除了该补丁(描述为here)。

该页面的评论说: 1.2.2-7发表于2008-06-19的无畏发布

python-mysqldb(1.2.2-7)不稳定;急=低

[Sandro Tosi]   * debian / control      - 列表中的项目行以2个空格开头,以避免重新格式化       在网页上(关闭:#480341)

[Bernd Zeimetz]   * 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 :(得分:3)

你可以将提交和关闭分开来进行连接......这不是很可爱,但确实如此。

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() 

答案 4 :(得分:1)

我遇到了与MySQL和Python类似的问题,对我有用的解决方案是将MySQL升级到5.0.27(在Fedora Core 6上;你的系统可以在不同的版本下正常工作)。

我尝试了很多其他的东西,包括修补Python库,但升级数据库要容易得多(我认为)更好的决定。

答案 5 :(得分:1)

我需要一种类似于Garret的解决方案,但对于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",))

答案 6 :(得分:0)

除了Liviu Chircu解决方案外,还将以下方法添加到DisconnectSafeCursor中:

def __getattr__(self, name):
    return getattr(self.cursor, name)

和原始光标属性(例如“ lastrowid”)将继续工作。

答案 7 :(得分:-3)

你还有其他人打赌它可以解决你自己与代码的连接问题。

一种方法是:

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