简体   繁体   English

Python:MySQL:处理超时

[英]Python: MySQL: Handling timeouts

I am using Python and mySQL, and there is a long lag between queries. 我使用的是Python和mySQL,查询之间存在很长的延迟。 As a result, I get an 'MySQL connection has gone away' error, that is wait_timeout is exceeded. 结果,我得到一个'MySQL连接已经消失'错误,即wait_timeout被超过。

This has been discussed eg in Gracefully handling "MySQL has gone away" 这已经在例如优雅地处理“MySQL已经消失”中进行了讨论

but this does not specifically answer my query. 但这并没有具体回答我的问题。

So my approach to handling this - I have wrapped all my sql execute statements in a method as - 所以我处理这个问题的方法 - 我已经将所有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()

I have several places in the code which calls this query. 我在代码中有几个地方调用此查询。 The thing is, I also have several cursors, so the method invocations look like- 问题是,我也有几个游标,所以方法调用看起来像 -

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

and so on 等等

I need a way to gracefully re-execute the query after the db has been started. 在db启动后,我需要一种方法来优雅地重新执行查询。 I could wrap the calls in an if statement, and re-execute so it would be 我可以在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

and then 然后

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

But this is clunky. 但这很笨重。 Is there a better way to do this? 有一个更好的方法吗? Thanks!!! 谢谢!!!

I tried Crasched's approach, which got me to a new OperationalError: 我尝试了Crasched的方法,这让我遇到了一个新的OperationalError:

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

My final solution was to first try the ping, and if another OperationalError was raised, to reconnect and recreate the cursor with the new connection, like so: 我的最终解决方案是首先尝试ping,如果引发了另一个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)

Back in business! 回到工作!

Python 2.7, MySQL 5.5.41 Python 2.7,MySQL 5.5.41

I had the same problem and wanted to wrap the exception to capture it but instead I solved it by using the following. 我有同样的问题,并希望包装异常捕获它,但我通过使用以下解决它。 Before calling the execute, call 在调用execute之前,请调用
self.con.ping(TRUE) self.con.ping(TRUE)

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

I can no longer find the original source material I found this out from, but this solved the problem immediately. 我再也找不到我发现的原始资料,但这立即解决了这个问题。

I was running into mystifying "MySQL server has gone away" errors, and here is my solution. 我遇到了神秘的“MySQL服务器已经消失”的错误,这是我的解决方案。

This solution will let you retry through MySQL errors, handle pretty much any type of query, include query variables in the query str or in a separate tuple, and collect and return all of the success and error messages you encounter along the way: 此解决方案将允许您重试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)))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM