国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

使django與數據庫保持長連接

2019-11-14 17:50:13
字體:
來源:轉載
供稿:網友

        最近遇到一個很蛋疼的問題,寫了一個后臺管理系統, 由于是后臺管理系統,所以使用頻率不是很高,當django程序在閑置一段時間后,再次打開后臺系統,就變得很慢,然后又好了。查了很多方面,從模板引擎到請求(request),再到django配置,nginx等等,都沒有查出原因。雖然也查過是不是數據庫的原因,但都因為查的不夠深入,沒有查出所以然。

        有一次在處理權限問題時,不斷地追朔源代碼,由于我使用的是dbroute來控制權限,最后定位到了這個db(具體目錄:/usr/local/lib/python2.7/dist-packages/django/db/__init__.py),里面的代碼有關于連接的,不看不知道,看了后菊花一緊。我去!原來django每次查詢的時候就連一次數據庫,而且查詢完成之后就立馬關掉,真搞不懂作者是怎么想的。每次查詢建一次連接不是很耗時間嗎?源代碼如下:

from django.conf import settingsfrom django.core import signalsfrom django.core.exceptions import ImPRoperlyConfiguredfrom django.db.utils import (ConnectionHandler, ConnectionRouter,    load_backend, DEFAULT_DB_ALIAS, DatabaseError, IntegrityError)__all__ = ('backend', 'connection', 'connections', 'router', 'DatabaseError',    'IntegrityError', 'DEFAULT_DB_ALIAS')if settings.DATABASES and DEFAULT_DB_ALIAS not in settings.DATABASES:    raise ImproperlyConfigured("You must define a '%s' database" % DEFAULT_DB_ALIAS)connections = ConnectionHandler(settings.DATABASES)router = ConnectionRouter(settings.DATABASE_ROUTERS)# `connection`, `DatabaseError` and `IntegrityError` are convenient aliases# for backend bits.# DatabaseWrapper.__init__() takes a dictionary, not a settings module, so# we manually create the dictionary from the settings, passing only the# settings that the database backends care about. Note that TIME_ZONE is used# by the PostgreSQL backends.# We load all these up for backwards compatibility, you should use# connections['default'] instead.class DefaultConnectionProxy(object):    """    Proxy for accessing the default DatabaseWrapper object's attributes. If you    need to access the DatabaseWrapper object itself, use    connections[DEFAULT_DB_ALIAS] instead.    """    def __getattr__(self, item):        return getattr(connections[DEFAULT_DB_ALIAS], item)    def __setattr__(self, name, value):        return setattr(connections[DEFAULT_DB_ALIAS], name, value)connection = DefaultConnectionProxy()backend = load_backend(connection.settings_dict['ENGINE'])# Register an event that closes the database connection# when a Django request is finished.def close_connection(**kwargs):    # Avoid circular imports    from django.db import transaction    for conn in connections:        # If an error happens here the connection will be left in broken        # state. Once a good db connection is again available, the        # connection state will be cleaned up.        transaction.abort(conn)        connections[conn].close()signals.request_finished.connect(close_connection)# Register an event that resets connection.queries# when a Django request is started.def reset_queries(**kwargs):    for conn in connections.all():        conn.queries = []signals.request_started.connect(reset_queries)# Register an event that rolls back the connections# when a Django request has an exception.def _rollback_on_exception(**kwargs):    from django.db import transaction    for conn in connections:        try:            transaction.rollback_unless_managed(using=conn)        except DatabaseError:            passsignals.got_request_exception.connect(_rollback_on_exception)

發現它是接收到了一個關閉信號后就立馬關閉,其實也就是每一次django請求,它就連接一次和查詢一次。網上查了下資料,有個人是這樣解決的:

在django項目中的__init__.py文件中加入如下代碼來實現:

from django.core import signals  from django.db import close_connection    # 取消信號關聯,實現數據庫長連接  signals.request_finished.disconnect(close_connection) 

它采用的原理是最后一行代碼相關的Signal對象,其中還有一個disconnect方法,對應實現取消信號關聯。

       我照著他的實現來做,發現不行,在閑置幾小時后,打開后臺依然需要10秒左右。由于我使用的是fastcgi來運行django,可能django在沒有動靜的時候,fastcgi就把它掛起,所以就還會去重新建立連接。如果使用supervisord來運行,估計不會。

       既然這個方法不行,那就再看一下它的源碼發現backends目錄下面有MySQLOracle,postgresql_psycopg2,sqlite3等,于是選擇msql進去看一下base.py文件。發現django是直接封裝MySQLdb,每創建一個MySQLdb對象其實也就進行了一次連接。能不能像線程池一樣,一次性創建多個MySQLdb對象呢?答案是肯定的。sqlalchemy有個pool可以讓數據庫保持長連接,那就直接把這個文件里的Database改成sqlalchemy的pool。當然,我們不能暴力地修改去修改源碼。因為這個模塊是用來建立數據庫連接的,所以可以獨立出來。其實很簡單,只需要修改base.py 文件幾處就行。實現方法如下:

        把django/db/backends/mysql目錄下的文件全部拷貝出來,放在項目的一個libs/mysql下面,然后修改base.py文件。找到

try:    import MySQLdb as Databaseexcept ImportError as e:    from django.core.exceptions import ImproperlyConfigured    raise ImproperlyConfigured("Error loading MySQLdb module: %s" % e)

這段代碼,在下面添加:

from sqlalchemy import poolDatabase = pool.manage(Database)

基本上就可以了。如果還想再修改,就找到

self.connection = Database.connect(**kwargs)

把它注釋掉,添加

            self.connection = Database.connect(                  host=kwargs.get('host', '127.0.0.1'),                  port=kwargs.get('port', 3306),                  user=kwargs['user'],                  db=kwargs['db'],                  passwd=kwargs['passwd'],                  use_unicode=kwargs['use_unicode'],                  charset='utf8'              )

再修改一下settings.py的數據庫配置,把django.db.backends.mysql改為libs.mysql。至此,世界美好了很多。如果精蟲上腦,可以移步至:來擼吧,你會發現世界更美好。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 彰武县| 许昌市| 宣化县| 临城县| 平凉市| 临城县| 丰都县| 正阳县| 河北区| 伊宁县| 宁夏| 剑阁县| 双流县| 连山| 怀宁县| 隆德县| 左权县| 济阳县| 泸州市| 信宜市| 大姚县| 木里| 晋中市| 会泽县| 壤塘县| 肥城市| 富阳市| 泽州县| 墨玉县| 永顺县| 山东| 威信县| 元氏县| 高州市| 晋宁县| 广平县| 沧州市| 阜新| 延长县| 石渠县| 罗田县|