利用SQLAlchemy为Django配置数据库连接池的两种实现方案
本文详细介绍如何在Django项目中引入SQLAlchemy构建数据库连接池,以解决高负载下频繁创建销毁连接的性能瓶颈。文章提供了两种修改Django源码的方法,重点解析了处理kwargs中字典类型导致的unhashable错误的关键代码修改,并附带了适用于Django 1.7与Python 2.7环境的配置示例。
通常情况下,Django框架在每次处理请求时都会建立新的数据库连接并在请求结束后释放。虽然这种机制在低负载场景下运行正常,但随着服务器并发请求量的增加,频繁地创建和销毁数据库连接会消耗大量系统资源,导致性能下降。为了解决这一问题,引入数据库连接池成为必要的优化手段。本文将以SQLAlchemy的连接池机制为例,展示如何实现Django数据库连接的持久化管理。
需要注意的是,实现连接池通常需要修改Django框架的底层代码,这属于对框架的侵入式修改,可能影响后续框架升级或维护。
方法 1
具体实现步骤如下:
首先,需要将Django源码中django/db/backends/mysql目录下的所有文件完整拷贝至项目内部的libs/mysql目录中,随后对该目录下的base.py文件进行修改。
另一种做法是将django/db/backends/mysql目录在django/db/backends/路径下复制一份,并重命名为mysql_pool文件夹。接着,将base.py文件中所有涉及mysql的import语句替换为mysql_pool。完成上述操作后,即可在项目的settings.py配置文件中直接指定'ENGINE':'django.db.backends.mysql_pool'来启用该后端。
找到
try:
import MySQLdb as Database
except ImportError as e:
from django.core.exceptions import ImproperlyConfigured
raise ImproperlyConfigured("Error loading MySQLdb module: %s" % e)
这段代码,在下面添加:
from sqlalchemy import pool Database = pool.manage(Database[,recycle=DATABASE_WAIT_TIMEOUT-1]) #其中DATABASE_WAIT_TIMEOUT为你定义的连接超时时间,必须小于等于mysql里面的wait_timeout()
结果如下
try:
import MySQLdb as Database
except ImportError as e:
from django.core.exceptions import ImproperlyConfigured
raise ImproperlyConfigured("Error loading MySQLdb module: %s" % e)
from sqlalchemy import pool
Database = pool.manage(Database)
然后找到get_connection_params(self)函数代码:
def get_connection_params(self):
kwargs = {
'conv':django_conversions,
'charset':utf8
}
...
修改为:
def get_connection_params(self):
kwargs = {
'charset':utf8
}
...
注意:如果不改变此处的kwargs,将会出现:TypeError:unhashable type:'dict' 的错误。
原样用kwargs传的话,sqlalchemy的pool会报unhashable错误,那是因为kwargs中有个key(conv)对应的value(django_conversions)是个字典,在pool中会把(key,value)组成元组作为新的key保存在pool中,但是因为value(django_conversions)是dict,不允许作为key的
在mysql里使用 show status 或 show processlist查看连接情况
方法 2
直接在settings.py同级目录下的init.py文件中添加如下代码
from django.conf import settings
from django.db.utils import load_backend
import sqlalchemy.pool as pool
import logging
pool_initialized=False
def init_pool():
if not globals().get('pool_initialized', False):
global pool_initialized
pool_initialized = True
try:
backendname = settings.DATABASES['default']['ENGINE']
backend = load_backend(backendname)
#replace the database object with a proxy.
backend.Database = pool.manage(backend.Database)
backend.DatabaseError = backend.Database.DatabaseError
backend.IntegrityError = backend.Database.IntegrityError
logging.info("Connection Pool initialized")
except:
logging.exception("Connection Pool initialization error")
init_pool()
然后修改django/db/backends/mysql/base.py文件
找到get_connection_params(self)函数代码:
修改为:
def get_connection_params(self):
kwargs = {
'charset':utf8
}
...
同理,不修改kwargs将会出现:TypeError:unhashable type:'dict' 的错误。
以上两种方法都要改变django的代码,有一定入侵性,第二种方法改变要小一点
django 1.7 python 2.7 sqlalchemy 1.0
这篇用sqlalchemy构建Django连接池的实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持本站。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













