如何启用MySQL客户端自动重新连接MySQLdb?
我遇到了PHP的做法:
my_bool reconnect = 1; mysql_options(&mysql, MYSQL_OPT_RECONNECT, &reconnect);
但MySQLdb(python-mysql)没有运气。
任何人都可以提供一个线索吗? 谢谢。
我通过创build一个包装cursor.execute()
方法的函数解决了这个问题,因为这是抛出MySQLdb.OperationalError
exception的原因。 上面的另一个例子意味着它是引发这个exception的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
我提出的解决scheme有问题,因为它没有发现exception。 我不知道为什么。
我已经用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
如果您使用的是Ubuntu Linux,则会在python-mysql软件包中添加一个修补程序,添加了设置相同MYSQL_OPT_RECONNECT选项的function(请参见此处 )。 我还没有尝试过。
不幸的是,由于与自动连接和转换( 这里描述)的冲突,补丁后来被删除。
该页面的评论说:1.2.2-7在2008-06-19发表intrepid-release
python-mysqldb(1.2.2-7)unstable; 急=低
[Sandro Tosi] * debian / control – 在描述中的列表项目行以2个空格开始,以避免重新格式化网页(closures:#480341)
[Bernd Zeimetz] * debian / patches / 02_reconnect.dpatch: – Dropping patch:Storm in 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.
你可以分开提交和closures连接…这不是可爱的,但它做到了。
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()
我有一个与MySQL和Python类似的问题,并且为我工作的解决scheme是将MySQL升级到5.0.27(在Fedora Core 6上;您的系统可以在不同的版本上正常工作)。
我尝试了很多其他的东西,包括修补Python库,但升级数据库要容易得多,(我认为)是一个更好的决定。
使用is_connected
方法,除非您检查错误string,否则由于其他原因可能引发OperationalError
,因此检查OperationalError
是否过于通用。
def is_connected(self): """Reports whether the connection to MySQL Server is available This method checks whether the connection to MySQL is available. It is similar to ping(), but unlike the ping()-method, either True or False is returned and no exception is raised. Returns True or False. """ try: self.cmd_ping() except: return False # This method does not raise return True
例:
class App: db_config = { 'host' : 'localhost', 'user' : 'example_user', 'password' : 'example_pass', 'database' : 'example_db', 'autocommit': True } dbc = None def getDBC(): if self.dbc is None: try: self.dbc = mysql.connector.connect(**self.db_config) return self.dbc except mysql.connector.Error as err: if err.errno == mysql.connector.errorcode.ER_ACCESS_DENIED_ERROR: print("Database access denied") elif err.errno == mysql.connector.errorcode.ER_BAD_DB_ERROR: print("Database does not exist") else: print(err) if not self.dbc.is_connected(): self.dbc.connect(**self.db_config) return self.dbc app = App() cursor = app.getDBC().cursor()
很明显,如果你将光标保持太久,它仍然会失败,如果这是一个问题,你需要重新devise你的应用程序,游标不应该被保留更长的时间然后真正需要,断开连接将会使游标意图在以前设置的MySQL中引用。
例如,这将是不好的:
cursor = app.getDBC().cursor() cursor.execute("BEGIN") // wait a long time, detect failure and reconnect try: cursor.execute("DELETE FROM x") cursor.execute("SOME BAD QUERY") except: cusror.execute("ROLLBACK")
回滚将失败,因为当数据库连接丢失时事务终止。 或者某些以前的操作由于连接丢失而自动回滚,导致数据库处于不一致状态。
你也可以打赌,你可以自己用代码来解决掉连接问题。
一种方法是:
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