Python可以使用MySQLdb进行数据库操作,但是每次连接MySQL数据库请求时,都是独立的去请求访问,相当浪费资源,而且访问数量达到一定数量时,对mysql的性能会产生较大的影响。实际使用中,通常会使用数据库的连接池来访问数据库达到资源复用的目的。这里介绍一下在django中如何实现数据库连接池。
DBUtils
DBUtils是一套python数据库连接池包,并允许对非线程安全的数据库接口进行线程安全包装。DBUtils来自Webware for Python。
下载地址:DBUtils
DBUtils提供两种外部接口:
- PersistentDB :提供线程专用的数据库连接,并自动管理连接。
- PooledDB :提供线程间可共享的数据库连接,并自动管理连接。
将下载下来的源码解压,放在应用程序根目录”database”中,修改SteadyDB.py文件,在类 SteadyDBConnection 中添加3个成员方法:
1 2 3 4 5 6 7 8 9
| def autocommit(self, *args, **kwargs): self._con.autocommit(*args, **kwargs)
def get_server_info(self): return self._con.get_server_info()
@property def encoders(self): return self._con.encoders
|
修改 PooledDB.py 和 PersistentDB.py 两个文件,将
1
| from DBUtils.SteadyDB import connect
|
改为:
1
| from .SteadyDB import connect
|
将Django中的mysql模块加入应用程序目录中,将backends目录下的 __init__.py文件和mysql目录复制到database目录下的db目录中,目录结构如下:
1 2 3 4 5 6 7 8 9
| 应用程序根目录 | | -- database | | -- DBUtils | -- db | | -- __init__.py | -- mysql
|
在mysql目录下添加pool.py文件,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| '''A connection pool of MySQL in Django 1.5 based on DBUtils.''' import MySQLdb from database.DBUtils.PooledDB import PooledDB
class ConnectionWrapper(object): def __init__(self, connection): self._conn = connection
def __getattr__(self, method): ''' 代理数据库连接的属性方法 ''' return getattr(self._conn, method)
def close(self): ''' 代理Django的关闭数据库连接 ''' self._conn.close()
class DBWrapper(object): def __init__(self, module): self._connection = None self._db = module self._pool = {}
def __getattr__(self, item): return getattr(self._db, item)
def _clear_connections(self, **kwargs): ''' 关闭已有连接 ''' conn = MySQLdb.connect(**kwargs) cursor = conn.cursor() sql = '' cursor.execute('show full processlist;') processlist = cursor.fetchall() for th in processlist: if th[3] == kwargs.get('db') and th[0] != conn.thread_id(): sql += 'kill %s;' % th[0] if len(sql.split(';')) > 1: cursor.execute(sql) cursor.close() conn.close()
def connect(self, *args, **kwargs): ''' 创建连接 ''' db = kwargs.get('db') if db not in self._pool: size = kwargs.get('size') if 'size' in kwargs: kwargs.pop('size') self._clear_connections(**kwargs) self._pool[db] = PooledDB(self._db, mincached=size, maxcached=size, *args, **kwargs) self._connection = self._pool[db].connection() return ConnectionWrapper(self._connection)
|
修改mysql目录下的 base.py 文件,在
1
| import MySQLdb as Database
|
下添加两行
1 2
| from .pool import DBWrapper Database = DBWrapper(Database)
|
修改类 DatabaseWrapper 中的方法 get_connection_params,在
1 2
| if settings_dict['PORT']: kwargs['port'] = int(settings_dict['PORT'])
|
下添加如下代码,使连接池支持”SIZE”参数
1 2
| if settings_dict.get('SIZE'): kwargs['size'] = int(settings_dict['SIZE'])
|
在settings.py配置文件的数据库项中,可以通过配置”SIZE”参数来指定连接池中某数据库的连接数量,如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| DATABASES = { 'default': { 'ENGINE': 'database.db.mysql', 'NAME': 'cartoon', 'USER': 'root', 'PASSWORD': 'root', 'HOST': '', 'PORT': '', 'SIZE': '10', 'OPTIONS': { 'init_command': 'SET default_storage_engine=INNODB', }, } }
|
至此,连接池改造完成。
运行程序,进入mysql命令行,执行
可以看到连接池里面所有的连接。
[^1]: 参考链接: Django实现MySQL连接池.
v1.5.2