AberSheeran
Aber Sheeran

Django 数据库自动重连

起笔自
所属文集: 杂记
共计 1263 个字符
落笔于

在非 Django web 服务里使用 Django ORM 的时候,时常会出现 (2006, 'MySQL server has gone away') 这样的报错。在一番查询之后,发现网上并没有出现什么好的解决办法,一般都是教你使用 django.db.close_old_connections 在查询前关闭所有连接。

这有一个十分严峻的问题,便是 Django 数据库连接是线程隔离的,你在一个线程里调用 close_old_connections 并不能影响到另一个线程,自然也无法修复这个问题。

一开始,我的解决思路是为 Django 引入一个连接池,使用的是网络上比较推崇的 djorm-ext-pool,但是它导致一个下午之后,数据库连接直接爆满,由于我不熟悉 SQLAlchemy,所以也无法修复这个问题。不过它的源代码给了我一点线索,让我得以了解 Django 内部的数据库连接工作原理。

import importlib

from django.conf import settings
from django.db.backends.utils import CursorWrapper


for name, config in settings.DATABASES.items():
    module = importlib.import_module(config["ENGINE"] + ".base")

    def ensure_connection(self):
        if self.connection is not None:
            try:
                with CursorWrapper(self.create_cursor(), self) as cursor:
                    cursor.execute("SELECT 1")
                return
            except Exception:
                pass

        with self.wrap_database_errors:
            self.connect()

    module.DatabaseWrapper.ensure_connection = ensure_connection

每次进行数据库操作前,Django 都会调用 ensure_connection 来确保数据库连接存在,但它并没有保证数据库连接有效,所以导致了会引发 (2006, 'MySQL server has gone away') 这样的问题。而我自行定义的函数里,通过执行 SQL SELECT 1 来检查数据库连接有效与否,如果数据库连接不存在或无效,则尝试创建一个数据库连接。

如果你觉得本文值得,不妨赏杯茶
优化 Windows Terminal 的使用体验
Django 禁止用户多客户端登录