Django實(shí)現(xiàn)MySQL連接池

注:筆者的Django版本為 1.9,Python版本為 2.7

一直想在Django中實(shí)現(xiàn)MySQL連接池帕识,在網(wǎng)上尋找良久無果,偶然之間晶姊,看到了一個(gè)帖子"讓Django支持?jǐn)?shù)據(jù)庫長連接(可以提高不少性能哦)"伪货,受到啟發(fā),既然可以實(shí)現(xiàn)長連接蒙挑,那么也可以實(shí)現(xiàn)連接池了愚臀,動(dòng)手姑裂!
  原理與鏈接帖子是一樣的,只是將數(shù)據(jù)庫的連接實(shí)例改為連接池的連接實(shí)例炭分。連接池使用DBUtils實(shí)現(xiàn)捧毛,但在Django中让网,需要對DBUtils進(jìn)行一點(diǎn)小改動(dòng)。
  一部分內(nèi)容是與鏈接帖子一樣的而账,在此為了完整性因篇,只做一次搬運(yùn)工。
  第一步吹缔,對DBUtils動(dòng)個(gè)小手術(shù)锯茄。
  DBUtils是一個(gè)實(shí)現(xiàn)數(shù)據(jù)庫連接池的庫肌幽,支持DB-API 2接口規(guī)范,點(diǎn)擊下載。解壓下載后的壓縮包讥蔽,將其中的DBUtils目錄加入應(yīng)用程序目錄中冶伞,筆者將其放在應(yīng)用程序根目錄"database"中步氏,Docs荚醒、Examples侯繁、Tests這3個(gè)目錄可以刪除贮竟,修改SteadyDB.py文件较剃,在類 SteadyDBConnection 中添加3個(gè)成員方法写穴,如下:

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 兩個(gè)文件啊送,將

from DBUtils.SteadyDB import connect

改為

from .SteadyDB import connect

第二步欣孤,"貍貓換太子"翔冀。
  將Django中的mysql模塊加入應(yīng)用程序目錄中,筆者將Django安裝在虛擬環(huán)境中搬瑰,位置是 Django虛擬環(huán)境路徑/lib/python2.7/site-packages/django/db/backends控硼,將backends目錄下的 __init__.py文件和mysql目錄復(fù)制到database目錄下的db目錄中,目錄結(jié)構(gòu)如下:

應(yīng)用程序根目錄
|
| -- database
     |
     | -- DBUtils
     | -- db
          |
          | -- __init__.py
          | -- mysql

在mysql目錄下添加pool.py文件翼悴,如下:

# coding:utf-8
'''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):
        ''' 代理數(shù)據(jù)庫連接的屬性方法 '''
        return getattr(self._conn, method)

    def close(self):
        ''' 代理Django的關(guān)閉數(shù)據(jù)庫連接 '''
        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):
        ''' 關(guān)閉已有連接 '''
        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):
        ''' 創(chuàng)建連接 '''
        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 文件,在

import MySQLdb as Database

下添加兩行

from .pool import DBWrapper
Database = DBWrapper(Database)

修改類 DatabaseWrapper 中的方法 get_connection_params误堡,在

if settings_dict['PORT']:
    kwargs['port'] = int(settings_dict['PORT'])

下添加如下代碼锁施,使連接池支持"SIZE"參數(shù)

if settings_dict.get('SIZE'):
    kwargs['size'] = int(settings_dict['SIZE'])

在settings.py配置文件的數(shù)據(jù)庫項(xiàng)中,可以通過配置"SIZE"參數(shù)來指定連接池中某數(shù)據(jù)庫的連接數(shù)量肩狂,如:

DATABASES = {
    'default': {
        # 'ENGINE': 'django.db.backends.mysql',
        'ENGINE': 'database.db.mysql',
        'NAME': 'cartoon',
        'USER': 'root',
        'PASSWORD': 'root',
        'HOST': '',
        'PORT': '',
        # 指定10個(gè)連接到cartoon庫
        'SIZE': '10',     # Default '0' means unlimit connection pool size
        'OPTIONS': {
            'init_command': 'SET default_storage_engine=INNODB',
        },
    }
}

至此姥饰,連接池改造完成列粪。
運(yùn)行程序,進(jìn)入mysql命令行篱竭,執(zhí)行

show full processlist;

可以看到已有10個(gè)cartoon庫的連接

Paste_Image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末掺逼,一起剝皮案震驚了整個(gè)濱河市瓤介,隨后出現(xiàn)的幾起案子赘那,更是在濱河造成了極大的恐慌氯质,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異辕漂,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)鸯乃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進(jìn)店門缨睡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來陈辱,“玉大人,你說我怎么就攤上這事拾并∨羟常” “怎么了?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵之碗,是天一觀的道長季希。 經(jīng)常有香客問我,道長博敬,這世上最難降的妖魔是什么峰尝? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮伦意,結(jié)果婚禮上硼补,老公的妹妹穿的比我還像新娘。我一直安慰自己已骇,他們只是感情好疾捍,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布乱豆。 她就那樣靜靜地躺著瑟啃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪岩榆。 梳的紋絲不亂的頭發(fā)上犹撒,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼刃跛。 笑死奠伪,一個(gè)胖子當(dāng)著我的面吹牛绊率,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播最仑,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼菱父!你這毒婦竟也來了浙宜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤裙品,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后焰轻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡揩懒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了智亮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,809評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡弃舒,死狀恐怖状原,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情颠区,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布器贩,位于F島的核電站央串,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏质和。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一厦酬、第九天 我趴在偏房一處隱蔽的房頂上張望瘫想。 院中可真熱鬧国夜,春花似錦、人聲如沸车吹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽乐埠。三九已至囚企,卻和暖如春瑞眼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背伤疙。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工掩浙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留秸歧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓谬墙,卻偏偏與公主長得像经备,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子侵蒙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評論 2 351

推薦閱讀更多精彩內(nèi)容