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) 关系

Django ORM按小时分组,不包括分钟。

django ORM 数据库连接配置

关于django操作orm的一些事--反向生成orm连接多个数据库

django入门 05 orm连接mySQL,调整表结构