Django ORM 连接超时的坑
Posted xiongsheng666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django ORM 连接超时的坑相关的知识,希望对你有一定的参考价值。
Django ORM 连接超时的坑
数据库链接丢失异常
django.db.utils.OperationalError: (2013, 'Lost connection to mysql server during query')
查询mysql全局变量SHOW GLOBAL VARIABLES;
可以看到wait_timeout
,此变量表示连接空闲时间,MySQL默认的时间是8小时
。如果客户端使用一个连接查询多次数据库,如果连续查询则没有问题,如果查询几次后停顿超过wait_timeout
后再次查询就会出现数据库连接丢失
Django中的数据库连接
Django程序接受到请求之后,在第一访问数据库的时候会创建一个数据库连接,直到请求结束,关闭连接。下次请求也是如此。因此,这种情况下,随着访问的并发数越来越高,就会产生大量的数据库连接。即,没收到一次请求,django就会建立一个数据库连接
解决方案
django关闭连接流程
对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
实现特定事件时执行此方法(类似于 触发器),两个特定事件是请求开始和请求结束。
如果报错的是在一次请求中,所以此法通常无效,仅仅是实现每个请求关闭并重新建立连接。
解决原理:
在每一次查询操作前,通过调用close_old_connections()
主动关闭闲置连接,主动关闭闲置连接,当再次操作数据库,会自动建立新的连接。
- 一般情况不会出现此类问题,因为一个请求中不间断进行数据库查询,无需每个请求调用此方法。
- 有时候一个请求中数据量较大,会查询数据库后进行一段时间其他(不涉及数据库)处理,比如先查询一些数据,然后进行超过MySQL的
wait_timeout
的长时间的操作。经过非常长时间,那么请求时建立的连接conn_1
已经被MySQL断开,而在项目中在经过长时间的操作后却仍然使用conn_1
,就会抛出异常,应该调用django.db.close_old_connections
关闭无效连接,重新连接MySQL,在操作数据库,防止连接丢失
具体方法
from django.db import close_old_connections
def func(request):
models.User.objects.filter(name='xxx')
time.sleep(9*60*60) # 模拟执行长时间耗时操作,时间超过MySQL的 wait_timeout
close_old_connections() # 先手动关闭无效时间
models.User.objects.filter(name='xxx') # 再进行查询
以上是关于Django ORM 连接超时的坑的主要内容,如果未能解决你的问题,请参考以下文章
MySQL 连接超时问题 - 使用 Hibernate 和 ORM 的 Tomcat 上的 Grails 应用程序
Django:获取每个用户的发票、费用、提款。 (ORM) 关系