Python和Django的OperationalError(2006年, 'MySQL服务

2019-07-17 20:37发布

原文:我最近已经开始从我的一些旧的代码,使MySQL OperationalErrors,似乎无法追溯的问题。 由于这是工作之前,我还以为它可能已被说破的东西软件更新。 我使用Python 2.7使用nginx的Django的runfcgi。 这是我原来的代码:

views.py

DBNAME = "test"
DBIP = "localhost"
DBUSER = "django"
DBPASS = "password"
db = MySQLdb.connect(DBIP,DBUSER,DBPASS,DBNAME)
cursor = db.cursor()

def list(request):
    statement = "SELECT item from table where selected = 1"
    cursor.execute(statement)
    results = cursor.fetchall()

我曾尝试以下,但它仍然无法正常工作:

views.py

class DB:
    conn = None
    DBNAME = "test"
    DBIP = "localhost"
    DBUSER = "django"
    DBPASS = "password"
def connect(self):
    self.conn = MySQLdb.connect(DBIP,DBUSER,DBPASS,DBNAME)
def cursor(self):
    try:
        return self.conn.cursor()
    except (AttributeError, MySQLdb.OperationalError):
        self.connect()
        return self.conn.cursor()

db = DB()
cursor = db.cursor()

def list(request):
    cursor = db.cursor()
    statement = "SELECT item from table where selected = 1"
    cursor.execute(statement)
    results = cursor.fetchall()

目前,我的唯一的解决方法就是做MySQLdb.connect()在使用MySQL各项功能。 另外我注意到,使用Django的时候manage.py runserver ,我不会有这样的问题,而nginx的将抛出这些错误。 我怀疑,我超时与连接,因为list()正在启动服务器最多几秒钟内调用。 在那里,我使用,将导致此破解软件的任何更新/有没有这方面的任何解决?

编辑:我意识到,我最近写了一篇中间件来守护进程的功能,这是问题的原因。 不过,我想不通为什么。 下面是中间件的代码

def process_request_handler(sender, **kwargs):
    t = threading.Thread(target=dispatch.execute,
        args=[kwargs['nodes'],kwargs['callback']],
        kwargs={})
    t.setDaemon(True)
    t.start()
    return
process_request.connect(process_request_handler)

Answer 1:

由于按照MySQL文档 ,因为服务器本身已关闭了连接你的错误消息时,客户端不能发送一个问题给服务器提出,最有可能的。 在最常见的情况下,服务器将关闭8小时后的(默认)的空闲连接。 这是在服务器端配置。

在MySQL文档给出了许多其他可能的原因,这可能是值得探讨,看看他们是否适合你的情况。

于调用备选connect()在每一个功能(这可能最终会不必要地创建新的连接)将是使用调查ping()的连接对象上的方法; 此测试与尝试的自动重新连接的选项的连接。 我挣扎着找到一些体面的文件为ping()网上的方法,但回答这个问题可能会有所帮助。

注意,自动地重新连接处理事务的时候,因为它出现的重新连接导致隐式回退(和似乎是主要的原因,为什么autoReconnect的不是MySQLdb的实现的功能)可能是危险的。



Answer 2:

有时,如果你看到“OperationalError:(2006年,‘MySQL服务器已经走了’)”,这是因为你发出查询太大。 这可能发生,例如,如果你存储在MySQL的会议,而你试图把一些在会议真正的大。 为了解决这个问题,就需要增加在MySQL中max_allowed_pa​​cket个设置的值。

默认值是1048576。

所以看到当前值默认,运行下面的SQL:

select @@max_allowed_packet;

临时设置一个新值,运行下面的SQL:

set global max_allowed_packet=10485760;

为了更永久修复这个问题,创建的/etc/my.cnf文件,其中至少以下几点:

[mysqld]
max_allowed_packet = 16M

编辑/etc/my.cnf中后,你需要重启MySQL或重新启动计算机,如果你不知道怎么办。



Answer 3:

检查是否被允许在一个线程创建MySQL连接对象,然后在另一个使用它。

如果它是被禁止使用threading.Local为每个线程的连接:

class Db(threading.local):
    """ thread-local db object """
    con = None

    def __init__(self, ...options...):
        super(Db, self).__init__()
        self.con = MySQLdb.connect(...options...)

db1 = Db(...)


def test():
    """safe to run from any thread"""
    cursor = db.con.cursor()
    cursor.execute(...)


Answer 4:

我一直在努力与这个问题了。 我不喜欢mysqlserver增加超时的想法。 autoReconnect的与CONNECTION_MAX_AGE无法正常工作或因为它被提及。 不幸的是我结束了包裹每一个查询数据库这样的方法

def do_db( callback, *arg, **args):
    try:
        return callback(*arg, **args)
    except (OperationalError, InterfaceError) as e:  # Connection has gone away, fiter it with message or error code if you could catch another errors
        connection.close()
        return callback(*arg, **args)

do_db(User.objects.get, id=123)  # instead of User.objects.get(id=123)

正如你可以看到我宁可选择捕捉异常不是查询它之前每一次查验数据库。 由于捕获异常情况很少见。 我希望Django的自动重新连接,但他们似乎拒绝了这个问题。



Answer 5:

几岁这段代码? Django的。从那以后至少0.96在设置中定义的数据库。 我唯一能想到的另一件事是多分贝的支持,这改变了事情有点,但即使是1.1或1.2。

即使您需要对某些意见特殊的数据库,我想你也许会更好,在设置中定义它。



Answer 6:

SQLAlchemy的现在有关于如何使用ping命令是悲观的连接的新鲜度有很大写了:

http://docs.sqlalchemy.org/en/latest/core/pooling.html#disconnect-handling-pessimistic

从那里,

from sqlalchemy import exc
from sqlalchemy import event
from sqlalchemy.pool import Pool

@event.listens_for(Pool, "checkout")
def ping_connection(dbapi_connection, connection_record, connection_proxy):
    cursor = dbapi_connection.cursor()
    try:
        cursor.execute("SELECT 1")
    except:
        # optional - dispose the whole pool
        # instead of invalidating one at a time
        # connection_proxy._pool.dispose()

        # raise DisconnectionError - pool will try
        # connecting again up to three times before raising.
        raise exc.DisconnectionError()
    cursor.close()

和测试,以确保上述工作:

from sqlalchemy import create_engine
e = create_engine("mysql://scott:tiger@localhost/test", echo_pool=True)
c1 = e.connect()
c2 = e.connect()
c3 = e.connect()
c1.close()
c2.close()
c3.close()

# pool size is now three.

print "Restart the server"
raw_input()

for i in xrange(10):
    c = e.connect()
    print c.execute("select 1").fetchall()
    c.close()


Answer 7:

我有这个问题,并没有改变我的配置选项。 我终于想通了,问题就出现49500条记录我的50000记录循环,因为这是我关于再次尝试的时间(在已尝试了很久以前)打我的第二个数据库。

所以我改变了我的代码,这样,每一个几千条记录,我再次碰到第二个数据库(以计数()一个非常小的表),并固定它。 毫无疑问,“平”或触摸数据库会的工作,以及其他一些手段。



Answer 8:

在我看来,对于这样的警告必须常见的问题,是一个事实,即你的应用程序已经达到的MySQL WAIT_TIMEOUT值。

我有我开发了一个应用程序PythonFLASK同样的问题,我解决了非常容易。

PS:我采用的是MySQL 5.7.14

$ grep timeout /etc/mysql/mysql.conf.d/mysqld.cnf 
# https://support.rackspace.com/how-to/how-to-change-the-mysql-timeout-on-a-server/
# wait = timeout for application session (tdm)
# inteactive = timeout for keyboard session (terminal)
# 7 days = 604800s / 4 hours = 14400s 
wait_timeout = 604800
interactive_timeout = 14400

一个重要的观察:如果你搜索通过MySQL的批处理模式下的变量,这些值将出现,因为它是。 但是,如果执行“SHOW VARIABLES LIKE‘等待%’;” 或“SHOW VARIABLES LIKE‘互动%’;”,配置为“interactive_timeout”的值,就会出现两个变量,我不知道为什么,但事实是,该配置在“/等各个变量的值/mysql/mysql.conf.d/mysqld.cnf”,将MySQL进程的尊重。

问候!



Answer 9:

此错误是神秘的,因为MySQL不报告为什么它断开,它就消失了。

它似乎有这种断线的原因很多。 一个我刚刚发现,如果查询字符串太大,服务器将断开连接。 这可能涉及max_allowed_packets设置。



Answer 10:

首先,你应该确保MySQL的会议和全球enviroments wait_timeoutinteractive_timeout值。 其次你的客户端应尝试重新连接到下面这些系统的环境值的服务器。



Answer 11:

这可能是由于DB连接在你的子线程得到复制主线程。 我用python的多库产卵不同的进程时所面临的同样的错误。 该连接对象在分叉进程之间复制和它导致的MySQL OperationalErrors时使DB在子线程调用。

这里有一个很好的参考解决这个问题: Django的多处理和数据库连接



Answer 12:

对我来说,这是发生在调试模式。

于是,我就在调试模式下持续连接,检出链接: Django的-文件-数据库-持久连接 。

在设置:

'default': {
       'ENGINE': 'django.db.backends.mysql',
       'NAME': 'dbname',
       'USER': 'root',
       'PASSWORD': 'root',
       'HOST': 'localhost',
       'PORT': '3306',
       'CONN_MAX_AGE': None
    },


文章来源: Python and Django OperationalError (2006, 'MySQL server has gone away')