Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python和Django操作错误(2006年,MySQL服务器消失了)_Python_Mysql_Django_Nginx_Django Middleware - Fatal编程技术网

Python和Django操作错误(2006年,MySQL服务器消失了)

Python和Django操作错误(2006年,MySQL服务器消失了),python,mysql,django,nginx,django-middleware,Python,Mysql,Django,Nginx,Django Middleware,我最近开始从一些旧代码中发现错误,似乎无法追溯问题。因为它以前是工作的,我想它可能是一个软件更新破坏了一些东西。我正在使用Python2.7和django runfcgi以及nginx。这是我的原始代码: 视图.py DBNAME = "test" DBIP = "localhost" DBUSER = "django" DBPASS = "password" db = MySQLdb.connect(DBIP,DBUSER,DBPASS,DBNAME) cursor = db.cursor()

我最近开始从一些旧代码中发现错误,似乎无法追溯问题。因为它以前是工作的,我想它可能是一个软件更新破坏了一些东西。我正在使用Python2.7和django runfcgi以及nginx。这是我的原始代码:

视图.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()
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()
我尝试了以下方法,但仍然无效:

视图.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()
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()
目前,我唯一的解决方法是在使用mysql的每个函数中执行
MySQLdb.connect()
。我还注意到,当使用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)

这个代码有多长时间了?Django至少从.96开始在设置中定义了数据库。我唯一能想到的另一件事是多数据库支持,它稍微改变了一些事情,但即使是1.1或1.2


即使您需要特定视图的特殊DB,我认为您最好在设置中定义它

检查是否允许在一个线程中创建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(...)
根据,当客户端无法向服务器发送问题时会发出错误消息,很可能是因为服务器本身已关闭连接。在最常见的情况下,服务器将在(默认)8小时后关闭空闲连接。这在服务器端是可配置的

报告给出了许多其他可能的原因,这些原因可能值得研究,以确定它们是否适合您的情况

除了在每个函数中调用
connect()
(这可能会导致不必要地创建新连接)之外,另一种方法是对连接对象使用
ping()
方法进行调查;这将使用尝试自动重新连接的选项测试连接。我很难在网上找到一些关于
ping()
方法的方法,但是答案可能会有所帮助


注意,在处理事务时,自动重新连接可能很危险,因为重新连接似乎会导致隐式回滚(这似乎是自动重新连接不是MySQLdb实现功能的主要原因).

SQLAlchemy现在有一篇关于如何使用ping对连接的新鲜度表示悲观的文章:

从那里

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()
有时,如果您看到“OperationalError:(2006,'MySQL服务器已经消失'”,那是因为您发出的查询太大。例如,如果您将会话存储在MySQL中,并且试图在会话中放入一些非常重要的内容,则可能会发生这种情况。要解决这个问题,您需要增加MySQL中max_allowed_数据包设置的值

默认值为1048576

因此,请查看默认值的当前值,运行以下SQL:

select @@max_allowed_packet;
set global max_allowed_packet=10485760;
要临时设置新值,请运行以下SQL:

select @@max_allowed_packet;
set global max_allowed_packet=10485760;
要更永久地解决此问题,请创建一个/etc/my.cnf文件,其中至少包含以下内容:

[mysqld]
max_allowed_packet = 16M

编辑/etc/my.cnf后,您需要重新启动MySQL,或者如果不知道如何重新启动计算机。

我也一直在努力解决这个问题。我不喜欢在mysqlserver上增加超时的想法。与
连接的自动重新连接\u MAX\u 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)

正如您所看到的,我更喜欢捕获异常,而不是在每次查询数据库之前对其进行ping。因为捕捉异常是一种罕见的情况。我希望django能够自动重新连接,但他们似乎解决了这个问题。

我遇到了这个问题,没有更改配置的选项。我最终发现问题出现在50000条记录循环中的49500条记录上,因为那是我再次尝试(在很久以前尝试过)访问第二个数据库的时间


所以我修改了我的代码,每隔几千条记录,我就会再次接触第二个数据库(使用一个非常小的表的count()),这就解决了它。毫无疑问,“ping”或其他触摸数据库的方式也会起作用。

关于此类警告最常见的问题是,您的应用程序已达到MySQL的
等待超时值

我在烧瓶应用程序上也有同样的问题

我是这样解决的:

$ 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批处理模式搜索变量,值将按原样显示。但是如果执行
则显示变量,如“wait%”
显示变量,如“交互%”
,为交互超时配置的值,将出现在两个变量中,我不知道为什么,但事实是,mysql将遵守在“/etc/mysql/mysql.conf.d/mysqld.cnf”为每个变量配置的值。

这个错误很神秘,因为mysql没有报告断开连接的原因,它就这样消失了


这种脱节似乎有很多原因。我刚刚发现的一个问题是,如果查询字符串太大,服务器将断开连接。这可能与
max\u allowed\u packets
设置有关。

首先,您应该确保MySQL会话和全局环境
wait\u timeout
interactive\u timeout
值。其次