问题

在Django中使用mysql偶尔会出现数据库连接丢失的情况,错误通常有如下两种
1. OperationalError: (2006, 'MySQL server has gone away')
1. OperationalError: (2013, 'Lost connection to MySQL server during query')

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

复现

下面用Django复现下次问题:

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

<code class="language-python">In[1]:import time
In[2]:from django.contrib.auth.models import User
In[3]:list(User.objects.filter(id=1))
Out[3]:[&lt;User: admin&gt;]
In[4]:time.sleep(15) # 模拟比较慢的代码(其中没有查询数据库的代码),或者空闲什么都不操作一段时间,此时间要比`wait_timeout`大一些
list(User.objects.filter(id=1))
Traceback (most recent call last): File &quot;&lt;ipython-input-4-3574ae8220ee&gt;&quot;, line 1, in &lt;module&gt;
list(User.objects.filter(id=1)) File &quot;/usr/lib/python3.6/site-packages/pymysql/connections.py&quot;, line 1037, in _read_bytes
CR.CR_SERVER_LOST, &quot;Lost connection to MySQL server during query&quot;)
django.db.utils.OperationalError: (2013, 'Lost connection to MySQL server during query')

寻求

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


<code class="language-python">DATABASES = {
&quot;default&quot;: {
'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()


<code class="language-python"># 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]: [&lt;User: admin&gt;]

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

  1. 一般情况不会出现此类问题,因为一个请求中不间断进行数据库查询,无需每个请求调用此方法,杞人忧天。
  2. 有时候一个请求中数据量较大,会查询数据库后进行一段时间其他(不涉及数据库)处理,比如先查询一些数据,然后将数据处理、生成excel、保存文件并生成url。已知此过长需要非常长时间,那么最终url保存数据库就最好先调用django.db.close_old_connections防止连接丢失

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

原文链接:https://my.oschina.net/watcher/blog/2994509

Django数据库连接丢失问题的更多相关文章

  1. mysql5 数据库连接丢失问题,autoReconnect=true不起作用

    The last packet successfully received from the server was 55,404,563 millise 方案1 定时器 方案2 修改连接池容量 mys ...

  2. django 数据库连接模块解析及简单长连接改造

    django 数据库连接模块解析及简单长连接改造工作中纯服务端的项目用到了线程池和django的ORM部分.django 的数据库连接在每一个线程中开启一份,并在查询完毕后自动关闭连接. 线程池处理任 ...

  3. django数据库连接快速配置

    DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql',#数据库驱动 'NAME': 'login_db',#数据库名字 'US ...

  4. Django 数据库连接配置(Oracle、Mysql)

    一.Django Oracle连接配置 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.oracle', 'NAME': 'DEMO' ...

  5. Django——数据库连接配置

    配置settings.py : DATABASES = { 'default': { #default表示默认,也可以指定app 'ENGINE': 'django.db.backends.mysql ...

  6. django 数据库连接出现的问题

    mysqlclient 1.3.3 or newer is required; you have 0.7.11: 解决方法: 将报错文件中的如下代码注释: if version < (1, 3, ...

  7. Django 数据库连接缓存的坑

    https://www.cnblogs.com/xcsg/p/11446990.html

  8. Django基础 - 修改默认SQLite3数据库连接为MySQL

    Django数据库连接默认为SQLite3,打开setting.py可以看到数据库部分的配置如下: DATABASES = { 'default': { 'ENGINE': 'django.db.ba ...

  9. Django入门开发之数据模型01

    1. Django安装 [root@HappyLau ~]# pip install django==1.8.2 2. 创建项目 [root@HappyLau html]# django-admin ...

随机推荐

  1. 使用CEfSharp之旅(7)CEFSharp 拦截 http 请求 websocket 内容

    原文:使用CEfSharp之旅(7)CEFSharp 拦截 http 请求 websocket 内容 版权声明:本文为博主原创文章,未经博主允许不得转载.可点击关注博主 ,不明白的进群19106581 ...

  2. 论一个X倒下了千千万万个X站起来了

        一个人倒下了,千千万万个人站起来了.起源自革命时期的标语.后来又被应用于各种激励的场景.     这句话在当时环境是好的,但是在无数人应用在不同场景,并且这些场景都不怎么好的时候.人的普遍思维 ...

  3. 数论,质因数,gcd——cf1033D 好题!

    直接筛质数肯定是不行的 用map<ll,ll>来保存质因子的指数 考虑只有3-5个因子的数的组成情况 必定是a=pq or a=p*p or a=p*p*p or a=p*p*p*p 先用 ...

  4. 19-11-2-M

    最后一个当然要模自己辣. %%%Miemengsb ZJ一下: 三道题没有一道会的,唯一的20还是T2输出$n/2$得的 咝…… T1一看,只会暴力. T2一看,像是状压,但是我是$dpsb$,于是弃 ...

  5. 深入浅出Mybatis系列(一)---Mybatis入门[转]

    最近两年 springmvc + mybatis 的在这种搭配还是蛮火的,楼主我呢,也从来没真正去接触过mybatis, 趁近日得闲, 就去学习一下mybatis吧. 本次拟根据自己的学习进度,做一次 ...

  6. LintCode刷题笔记-- A+B problem

    标签: 位运算 描述 Write a function that add two numbers A and B. You should not use + or any arithmetic ope ...

  7. SPSS实例教程:多重线性回归,你用对了么

    SPSS实例教程:多重线性回归,你用对了么 在实际的医学研究中,一个生理指标或疾病指标往往受到多种因素的共同作用和影响,当研究的因变量为连续变量时,我们通常在统计分析过程中引入多重线性回归模型,来分析 ...

  8. fastjson过滤字段

    1.注解(字段上添加) @JSONField(serialize=false) 2.过滤器 PropertyFilter propertyFilter = new PropertyFilter() { ...

  9. <scrapy爬虫>爬取腾讯社招信息

    1.创建scrapy项目 dos窗口输入: scrapy startproject tencent cd tencent 2.编写item.py文件(相当于编写模板,需要爬取的数据在这里定义) # - ...

  10. 「loj#6261」一个人的高三楼

    题目 显然存在一个这样的柿子 \[S^{(k)}_i=\sum_{j=1}^iS^{(k-1)}_j\] 我们可以视为\(S^{(k)}\)就是由\(S^{(k-1)}\)卷上一个长度为\(n\)全是 ...