Python和Django操作错误(2006年,MySQL服务器消失了)
我最近开始从一些旧代码中发现错误,似乎无法追溯问题。因为它以前是工作的,我想它可能是一个软件更新破坏了一些东西。我正在使用Python2.7和django runfcgi以及nginx。这是我的原始代码: 视图.pyPython和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()
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
值。其次