如何检测 MySQL 中的临时故障?

Posted

技术标签:

【中文标题】如何检测 MySQL 中的临时故障?【英文标题】:How to detect temporary failures in MySQL? 【发布时间】:2018-11-02 19:04:20 【问题描述】:

我正在编写一个 python 实用程序来在 mysql 服务器上执行大量请求。如果我们检测到临时故障(例如,如果网络暂时关闭),则要求之一是重试查询(一段时间后)。我们使用MySQL Connector/Python。

基本思路是:

try:
    cursor = cnx.get_cursor()
except:
    # If error is temporary, wait and retry
    # else stop
try:  
    cursor.execute(request)
except:
    # If error is temporary, wait and retry
    # else stop

游标的创建和请求分开处理,便于错误处理。

问题在于,似乎很难发现值得重试的情况。 AFAI,MySQL 错误和 MySQL 连接器/Python 中的PEP 249 errors 之间的映射不容易处理。例如,错误2013(丢失与服务器的连接)映射到InterfaceError,而错误2006(服务器已离开)映射到OperationalError,这两种情况都值得重试。

所以我想知道是否有一种常规的方式(可能基于errno)来对此类错误进行分类。

【问题讨论】:

对不起,我忘记了标题中的一个重要词。 您的赏金中有错字,应该是“列表”而不是“最少”。让我一时糊涂。 如果使用事务,try/except 需要包含整个事务;这将解决死锁等问题。 @ArranCudbard-Bell 抱歉打错了。你知道怎么改吗? 我想说“临时”错误的概念是特定于应用程序的,制作自定义 is_worth_retrying 函数可能是有意义的(也许,它也可以指定等待时间,视问题而定)。例如,“服务器已消失”错误肯定是 OperationalError,因为这意味着您的查询执行时间过长,超出了服务器的耐心。是否值得重试,还是应该重写查询或重新配置服务器?由您决定。 【参考方案1】:
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

for i in range(0,100):
    while True:
        try:
            result = sock.connect_ex(('irc.myserver.net', 6667))
            if result == 0:
                break
            else:
                continue

您可以在进行数据传输之前或之后尝试这种事情吗?您可以检查数据库之间的连接,然后如果一切正常,您可以执行查询

【讨论】:

【参考方案2】:

遗憾的是,您必须编写自己的类来处理这个问题。 此代码为 alpha/beta 版本。

有用的方法、建议或其他有用的东西。

例如: 这个线程安全吗? 这个多类安全吗?

用法:

connection = mysqlc.Mysql(host='192.168.1.1', user='user', password='password', database='database')

connection.sql(sql) 命令尽力自动处理错误。

---------班级------------------

from mysql.connector import errorcode
import mysql

import mysql.connector



class Mysql(object):
    __instance = None

    __host = None
    __user = None
    __password = None
    __database = None

    __session = None
    __connection = None

    def __new__(cls, host,user,password,database,*args, **kwargs):
        if not cls.__instance:
            cls.__instance = super(Mysql, cls).__new__(cls, *args, **kwargs)
        return cls.__instance

    def __init__(self, host='localhost', user='root', password='', database=''):
        self.__host = host
        self.__user = user
        self.__password = password
        self.__database = database

    #Open connection with database
    def _open(self):
        try:
            cnx = mysql.connector.connect(host=self.__host, user=self.__user, password=self.__password,
                                          database=self.__database)
            self.__connection = cnx
            self.__session = cnx.cursor()
        except mysql.connector.Error as err:
            if err.errno == errorcode.ER_ACCESS_DENIED_ERROR:
                print('Something is wrong with your user name or password')
            elif err.errno == errorcode.ER_BAD_DB_ERROR:
                print('Database does not exists')
            elif err.errno == 2003:
                print("No connection to host")
            else:
                print("Some other error" )
# err 1698 access denied
                print(err)

    def _close(self):
        self.__session.close()
        self.__connection.close()

    def sql(self, sql, *args, **kwargs):
        values = None
        arg=len(args)
        kwarg=len(kwargs)
        if self.__connection is None:
           self._open() 
        self.__connection.ping(reconnect=True,attempts=3,delay=2)
        while True:
            try:
                 if arg == 0 and kwarg ==0:
                    self.__session.execute(sql)
                 if arg == 1 and kwarg == 0:
#                    self.__session.execute(temp)
                    self.__session.execute(sql, args[0])

            except InterfaceError as err:
                       self._open()
            except OprationalError as err:
                       self._open()
            except mysql.connector.Error as err:
#                 print("err:")
#                 print(+err.errno)
                 print("error")
                 print(format(err))
                 if err.errno == -1:
                     self._open()

                 if err.errno ==2003:
                     try:
                          self.__connection.ping(reconnect=True,attempts=3,delay=2)
                     except mysql.connector.Error as err:
                          print("error")
                          print(err.errno)
                          self._open()
            except:
                   print(sys.exc_info()[0])
            else:
                self.__connection.commit()
                break


        #row=self.__session.fetchall()
        #print(row)
#        self.__connection.commit()
        return self.__session.lastrowid

【讨论】:

以上是关于如何检测 MySQL 中的临时故障?的主要内容,如果未能解决你的问题,请参考以下文章

mysql如何创建临时表

mysql语句的简化:from中的临时表作为where中的条件

如何删除没有临时表的 MySQL 表中的所有重复记录

如何编写一个 MySQL 查询,该查询返回一个临时列,其中包含与该行相关的项目是不是存在于另一个表中的标志

MySQL中的两种临时表

mysql 临时表的建立和用途