2012-11-26 69 views
3

我正在使用Python和mySQL,并且查询之间有很长时间的滞后。结果,我得到一个'MySQL连接已经消失'的错误,即wait_timeout超出。Python:MySQL:处理超时

这已经在例如在 Gracefully handling "MySQL has gone away"

但这并不具体回答我的查询。

所以我的方法来处理这个 - 我已经包裹我所有的SQL的方法执行语句 -

def __execute_sql(self,sql,cursor): 
    try: 
     cursor.execute(sql) 

    except MySQLdb.OperationalError, e:    
     if e[0] == 2006: 
      self.logger.do_logging('info','DB', "%s : Restarting db" %(e)) 
      self.start_database() 

我在调用该查询的代码的几个地方。关键是,我也有几个游标,因此该方法调用看起来喜欢 -

self.__execute_sql(sql,self.cursor_a) 
self.__execute_sql(sql,self.cursor_b) 

我需要一种方法分贝启动后优雅地重新执行查询。 if语句我可以换的电话在,并重新执行所以这将是

def __execute_sql(self,sql,cursor): 
    try: 
     cursor.execute(sql) 
     return 1 
except MySQLdb.OperationalError, e:    
    if e[0] == 2006: 
     self.logger.do_logging('info','DB', "%s : Restarting db" %(e)) 
     self.start_database() 
     return 0 

然后

if (self.__execute_sql(sql,self.cursor_a) == 0): 
    self.__execute_sql(sql,self.cursor_a) 

但这是笨重。有一个更好的方法吗? 谢谢!

回答

2

我有同样的问题,并希望包装异常捕获它,而是我通过使用以下解决它。 调用执行之前,调用
self.con.ping(TRUE)

http://www.neotitans.com/resources/python/mysql-python-connection-error-2006.html http://mysql-python.sourceforge.net/MySQLdb.html

我再也找不到我发现了这一点,从原来的源材料,但这种立即解决了这个问题。

+1

运行查询被认为是反模式是浪费资源和不可靠之前执行ping:https://www.percona.com/blog/2010/05/05/checking-for-a-实时数据库连接认为有害/ –

2

我试图Crasched的做法,这让我到一个新的OperationalError:

OperationalError: (2013, 'Lost connection to MySQL server during query')

我最终的解决办法是先试平,如果另一OperationalError提高后,重新连接并重新创建光标新的连接,如下所示:

try: 
    self.connection.ping(True) 
except MySQLdb.OperationalError: 
    self.connection = MySQLdb.connect(
     self.db_host, 
     self.db_user, 
     self.db_passwd, 
     self.db_dbase, 
     self.db_port) 
    # reconnect your cursor as you did in __init__ or wherever  
    self.cursor = self.connection(
     MySQLdb.cursors.DictCursor) 

重新生意!

的Python 2.7,MySQL的41年5月5日

+2

在运行查询之前进行Ping操作被认为是一种浪费资源并且不可靠的反模式:https://www.percona.com/blog/2010/05/05/checking-for -a-live-database-connection-considered-harmful/ –

+2

@JeffWidman - 有用的不要;什么是做 - 而不是? – kiminoa

+0

@kiminoa - 尝试执行查询,并捕获任何MySQL错误,在这种情况下,请重新尝试查询。 –

0

我也陷入了神秘的“MySQL服务器消失”的错误,这里是我的解决方案。

此解决方案将允许您重试MySQL错误,处理几乎任何类型的查询,将查询变量包含在查询str中或单独的元组中,并收集并返回所有您遇到的成功和错误消息方法:

def execute_query(query_str, values=None): 
    # defaults 
    num_affected_rows = 0 
    result_rows = None 
    success = False 
    message = "Error executing query: {}".format(query_str) 
    # run the query 
    try: 
    mysql_conn = get_existing_mysql_connection() 
    cur = mysql_conn.cursor() 
    if values == None or len(values) < 1: 
     num_affected_rows = cur.execute(query_str) 
    else: 
     num_affected_rows = cur.execute(query_str, values) 
    result_rows = cur.fetchall() # only relevant to select, but safe to run with others 
    cur.close() 
    mysql_conn.commit() 
    success = True 
    message = "Mysql success for query: {}".format(query_str) 
    except BaseException as e: 
    message = "Mysql error: {}; for query: {}".format(repr(e), query_str) 
    return (success, num_affected_rows, result_rows, message) 


def execute_query_with_retry(query_str, values=None, num_tries=3, message=""): 
    # defaults 
    success = False 
    num_affected_rows = 0 
    result_rows = None 
    this_message = "Error executing query: {}".format(query_str) 
    # should we still try? 
    if num_tries < 1: 
    this_message = "Ran out of tries for query: {}".format(query_str) 
    return (False, 0, None, message + '; ' + this_message) 
    num_tries_after_this = num_tries - 1 
    # try to execute query 
    try: 
    (success, num_affected_rows, result_rows, this_message) = execute_query(query_str, values) 
    except BaseException as e: 
    success = False 
    # handle success or failure 
    if success == True: 
    return (True, num_affected_rows, result_rows, message + '; ' + this_message) 
    else: 
    open_new_mysql_connection() # reconnect using password etc. 
    return(execute_query_with_retry(query_str, values=values, num_tries=num_tries_after_this, message=(message + '; ' + this_message)))