在非 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
来检查数据库连接有效与否,如果数据库连接不存在或无效,则尝试创建一个数据库连接。