2012-11-26 66 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)))