django默认使用短连接(conn_max_age=0),每次请求新建并关闭连接;启用持久连接需显式设置conn_max_age为正整数或none,但必须小于数据库空闲超时值(如mysql wait_timeout),否则易触发连接意外关闭错误。

直接上结论:Django 默认是短连接(CONN_MAX_AGE=0),每请求建一次、关一次;要复用连接,必须显式设置 CONN_MAX_AGE 为正整数或 None,但不能盲目设高,否则会和数据库空闲超时冲突,反而引发 OperationalError: server closed the connection unexpectedly 这类错误。
CONN_MAX_AGE 设置多少才安全
关键不是“想复用多久”,而是“数据库允许空闲多久”。MySQL 默认 wait_timeout=28800(8 小时),但很多生产环境 DBA 会调低到 60–300 秒;PostgreSQL 的 tcp_keepalives_idle 和连接池(如 pgBouncer)也会干预实际空闲时长。
实操建议:
- 先查数据库实际空闲超时值:
SHOW VARIABLES LIKE 'wait_timeout';(MySQL)或SHOW tcp_keepalives_idle;(PostgreSQL) -
CONN_MAX_AGE值应比该超时小 10–20 秒,例如数据库设了 60 秒,就配CONN_MAX_AGE = 45 - 绝对不要在开发模式(
runserver)里设CONN_MAX_AGE,因为每个请求起一个新线程,连接无法复用,还会累积泄漏 - ASGI 部署(如 Uvicorn + Django 4.2+)下禁用
CONN_MAX_AGE,改用数据库原生连接池(如 pgBouncer)或第三方包(如django-db-connection-pool)
为什么设置了 CONN_MAX_AGE 却没看到连接复用
Django 的连接复用基于 threading.local,本质是“每线程一个连接”。如果部署模型不匹配,配置就失效。
常见失效场景:
- Gunicorn 启动参数用了
--threads但没配--workers,导致线程数远超预期,连接数爆炸 - 用
gevent或eventlet打补丁后,threading.local失效,必须配合gevent.local补丁或换连接池 - 某些中间件(如自定义日志、审计)在 request 开始前就访问了数据库,触发连接创建,但后续逻辑又在不同线程执行,导致复用断链
- DEBUG=True 且启用了
django-debug-toolbar,它的 SQL 面板可能强制关闭/重建连接,掩盖复用效果——上线前务必关掉
CONN_HEALTH_CHECKS 要不要开
开启 CONN_HEALTH_CHECKS = True 会让 Django 在每次请求开头对连接做一次简单查询(如 SELECT 1),确认是否还活着。它能缓解数据库重启后首请求失败的问题,但有代价。
权衡点:
- 适合数据库不稳定、或经常人工维护的环境(如测试库、DBA 频繁操作的 staging)
- 高并发写多读少场景慎用,额外一次 round-trip 可能放大延迟
- 仅当
CONN_MAX_AGE > 0时才有意义;设为 0 或None时健康检查被忽略 - 它不替代连接池,也不能防止连接被防火墙静默中断(需靠
tcp_keepalive系统级配置)
最易被忽略的一点:CONN_MAX_AGE 是按数据库配置项单独生效的,如果你有多个数据库路由(DATABASES['replica']),必须对每个都显式设置,漏掉一个就会让那路流量持续新建短连接,压测时这个“漏网之鱼”往往最先打爆数据库。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











