Django数据库连接丢失问题的解决方法


Posted in Python onDecember 29, 2018

问题

在Django中使用mysql偶尔会出现数据库连接丢失的情况,错误通常有如下两种

OperationalError: (2006, 'MySQL server has gone away')
OperationalError: (2013, 'Lost connection to MySQL server during query')

查询mysql全局变量SHOW GLOBAL VARIABLES;可以看到wait_timeout,此变量表示连接空闲时间。如果客户端使用一个连接查询多次数据库,如果连续查询则没有问题,如果查询几次后停顿超过wait_timeout后再次查询就会出现数据库连接丢失。

复现

下面用Django复现下次问题:

将mysql的wait_timeout设置为10秒,然后进入django shell模拟查询(以下错误信息只保留了部分)

In[1]:import time
In[2]:from django.contrib.auth.models import User
In[3]:list(User.objects.filter(id=1))
Out[3]:[<User: admin>]
In[4]:time.sleep(15) # 模拟比较慢的代码(其中没有查询数据库的代码),或者空闲什么都不操作一段时间,此时间要比`wait_timeout`大一些
list(User.objects.filter(id=1))
Traceback (most recent call last):

  File "<ipython-input-4-3574ae8220ee>", line 1, in <module>
    list(User.objects.filter(id=1))

  File "/usr/lib/python3.6/site-packages/pymysql/connections.py", line 1037, in _read_bytes
    CR.CR_SERVER_LOST, "Lost connection to MySQL server during query")
django.db.utils.OperationalError: (2013, 'Lost connection to MySQL server during query')

寻求

那么以上问题就基本说明了是空闲时间过长导致的错误。

django为了减少不必要的数据库连接、关闭,复用了数据库连接,当开始一个请求后建立一个连接池存放连接,之后此次请求都复用一个连接。那猜测就是django保存连接的比wait_timeout长了,如果保存时间短一些就可以重新建立连接避免此错误了。 没错,官方文档也已经说明了此问题,设置数据库 CONN_MAX_AGE参数,示例:

DATABASES = {
 "default": {
 'ENGINE': 'django.db.backends.mysql',
 'NAME': '',
 'USER': '',
 'PASSWORD': '',
 'HOST': '',
 'CONN_MAX_AGE': 9 # 比wait_timeout小一些
 }
}

当我们测试后却发现,事情并非想想中那么简单。为何错误依旧出现?这一切的背后, 是人性的扭曲还是道德的沦丧?敬请收看下节《突破》。

突破

对django源码中CONN_MAX_AGE进行了一番搜索,顺藤摸瓜发现了django关闭失效连接的方法django.db.close_old_connections():

# Register an event to reset transaction state and close connections past
# their lifetime.
def close_old_connections(**kwargs):
 for conn in connections.all():
  conn.close_if_unusable_or_obsolete()

signals.request_started.connect(close_old_connections)
signals.request_finished.connect(close_old_connections)

重点在最后两行,通过signal实现特定事件时执行此方法,两个特定事件顾名思义是请求开始和请求结束。而我们报错的是在一次请求中,所以此法通常无效,仅仅是实现每个请求关闭并重新建立连接。

解决

复现问题的django shell不要关闭,继续执行如下代码:

In[5]:from django.db import close_old_connections
In[6]:close_old_connections()
In[7]:list(User.objects.filter(id=1))
Out[7]: [<User: admin>]

调用django.db.close_old_connections后再次查询就没有错误了。 那么我们要避免此错误就要执行每个数据库查询前调用django.db.close_old_connections方法。

一般情况不会出现此类问题,因为一个请求中不间断进行数据库查询,无需每个请求调用此方法,杞人忧天。

有时候一个请求中数据量较大,会查询数据库后进行一段时间其他(不涉及数据库)处理,比如先查询一些数据,然后将数据处理、生成excel、保存文件并生成url。已知此过长需要非常长时间,那么最终url保存数据库就最好先调用django.db.close_old_connections防止连接丢失

题外话 实际上②所述情况最好从根本上解决处理慢的问题,也可以换作异步处理,从根本上解决问题。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Flask入门教程实例:搭建一个静态博客
Mar 27 Python
python使用MySQLdb访问mysql数据库的方法
Aug 03 Python
HTML中使用python屏蔽一些基本功能的方法
Jul 07 Python
python在TXT文件中按照某一字符串取出该字符串所在的行方法
Dec 10 Python
python实现得到当前登录用户信息的方法
Jun 21 Python
python调用自定义函数的实例操作
Jun 26 Python
详解Python二维数组与三维数组切片的方法
Jul 18 Python
python zip,lambda,map函数代码实例
Apr 04 Python
Python使用jpype模块调用jar包过程解析
Jul 29 Python
如何使用pycharm连接Databricks的步骤详解
Sep 23 Python
Pandas中DataFrame交换列顺序的方法实现
Dec 14 Python
python opencv人脸识别考勤系统的完整源码
Apr 26 Python
Python Cookie 读取和保存方法
Dec 28 #Python
Python编程flask使用页面模版的方法
Dec 28 #Python
Python编程中flask的简介与简单使用
Dec 28 #Python
Python3 Post登录并且保存cookie登录其他页面的方法
Dec 28 #Python
Python3 使用cookiejar管理cookie的方法
Dec 28 #Python
Python编程在flask中模拟进行Restful的CRUD操作
Dec 28 #Python
python获取服务器响应cookie的实例
Dec 28 #Python
You might like
php excel类 phpExcel使用方法介绍
2010/08/21 PHP
php简单生成一组与多组随机字符串的方法
2017/05/09 PHP
php封装单文件上传到数据库(路径)
2017/10/15 PHP
Laravel 解决composer相关操作提示php相关异常的问题
2019/10/23 PHP
解决extjs在firefox中关闭窗口再打开后iframe中js函数访问不到的问题
2008/11/06 Javascript
html组件不可输入(只读)同时任何组件都有效
2013/04/01 Javascript
PHP+jQuery+Ajax实现多图片上传效果
2015/03/14 Javascript
轻松学习jQuery插件EasyUI EasyUI表单验证
2015/12/01 Javascript
Bootstrap每天必学之轮播(Carousel)插件
2016/04/25 Javascript
一个非常好用的文字滚动的案例,鼠标悬浮可暂停[两种方案任选]
2016/12/01 Javascript
nodejs 实现钉钉ISV接入的加密解密方法
2017/01/16 NodeJs
Vue实现一个无限加载列表功能
2018/11/13 Javascript
jQuery实现网页拼图游戏
2020/04/22 jQuery
利用原生JavaScript实现造日历轮子实例代码
2019/05/08 Javascript
微信小程序收货地址API兼容低版本解决方法
2019/05/18 Javascript
layui table复选框禁止某几条勾选的实例
2019/09/20 Javascript
Postman动态获取返回值过程详解
2020/06/30 Javascript
js实现微信聊天界面
2020/08/09 Javascript
[05:31]DOTA2英雄梦之声_第08期_莉娜
2014/06/23 DOTA
Python中的条件判断语句与循环语句用法小结
2016/03/21 Python
python脚本实现xls(xlsx)转成csv
2016/04/10 Python
Python从文件中读取数据的方法讲解
2019/02/14 Python
python logging 日志的级别调整方式
2020/02/21 Python
基于Python绘制美观动态圆环图、饼图
2020/06/03 Python
CSS3弹性盒模型开发笔记(一)
2016/04/26 HTML / CSS
联想韩国官网:Lenovo Korea
2018/05/10 全球购物
澳大利亚在线消费电子产品商店:TobyDeals
2020/01/05 全球购物
土木工程建筑专业毕业生求职信
2013/10/21 职场文书
广告学毕业生求职信
2014/01/30 职场文书
安全生产汇报材料
2014/02/17 职场文书
金融专业求职信
2014/08/05 职场文书
公司感谢信范文
2015/01/22 职场文书
怀孕辞职信怎么写
2015/02/28 职场文书
2015年物流客服工作总结
2015/07/27 职场文书
青年志愿者活动感想
2015/08/07 职场文书
八年级数学教学反思
2016/02/17 职场文书