【发布时间】:2010-09-17 12:05:11
【问题描述】:
我遇到了 PHP 的做法:
my_bool reconnect = 1;
mysql_options(&mysql, MYSQL_OPT_RECONNECT, &reconnect);
但 MySQLdb (python-mysql) 没有运气。
谁能给个提示?谢谢。
【问题讨论】:
我遇到了 PHP 的做法:
my_bool reconnect = 1;
mysql_options(&mysql, MYSQL_OPT_RECONNECT, &reconnect);
但 MySQLdb (python-mysql) 没有运气。
谁能给个提示?谢谢。
【问题讨论】:
如果您使用的是 ubuntu Linux,python-mysql 软件包中添加了一个补丁,该补丁添加了设置相同 MYSQL_OPT_RECONNECT 选项的功能(请参阅here)。不过我没试过。
不幸的是,由于与自动连接和事务的冲突(描述为here),该补丁后来被删除。
该页面上的 cmets 说: 1.2.2-7 intrepid-release于2008-06-19发布
python-mysqldb (1.2.2-7) 不稳定;紧迫性=低
[桑德罗·托西] * Debian/控制 - 描述中的列表项目行以 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.
【讨论】:
您也可以自己用代码解决掉线问题。
一种方法如下:
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
【讨论】:
我在使用 MySQL 和 Python 时遇到了类似的问题,对我有用的解决方案是将 MySQL 升级到 5.0.27(在 Fedora Core 6 上;您的系统可能在不同版本下也能正常工作)。
我尝试了很多其他方法,包括修补 Python 库,但升级数据库要容易得多,而且(我认为)是一个更好的决定。
【讨论】:
我通过创建一个包装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
【讨论】:
conn.open 可以解决问题……但这有效。
@variables 和SETtings。此外,一个半完成的交易将是ROLLBACK'd。这可能会导致一些混乱。
OperationalError: (1054, "Unknown column 'countryy' in 'field list'"). 也许这在 2009 年有所不同,但只是说。
您可以将连接的提交和关闭分开......这并不可爱,但它确实做到了。
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()
【讨论】:
我对建议的解决方案有疑问,因为它没有捕获异常。我不知道为什么。
我已经用我认为更简洁的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
【讨论】:
我需要一个与 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",))
【讨论】:
除了 Liviu Chircu 解决方案...在 DisconnectSafeCursor 中添加以下方法:
def __getattr__(self, name):
return getattr(self.cursor, name)
并且像“lastrowid”这样的原始光标属性将继续工作。
【讨论】: