django 數(shù)據(jù)庫連接模塊解析及簡單長連接改造方法
工作中純服務(wù)端的項目用到了線程池和django的ORM部分。django 的數(shù)據(jù)庫連接在每一個線程中開啟一份,并在查詢完畢后自動關(guān)閉連接。
線程池處理任務(wù)時,正常使用的連接中不會被關(guān)閉,但由于數(shù)據(jù)庫端有最長連接時間的限制(默認(rèn)為8小時),在超時后會發(fā)生InterfaceError: (0, '')(連接關(guān)閉后使用連接/游標(biāo))或Error(2006, 'MySQL server has gone away')(mysql 服務(wù)器主動關(guān)閉連接)這類錯誤,所以一般會在每個任務(wù)線程中調(diào)用django.db.connection.close()進行關(guān)閉操作。
但對于頻繁進行數(shù)據(jù)庫連接并操作數(shù)據(jù)庫的業(yè)務(wù),反復(fù)創(chuàng)建連接并不是好的選擇,這種場景下可以考慮將連接改造為長連接。
1. django 代碼的閱讀筆記
django.db.__init__.py #對象: connections = ConnectionHandler() connection = DefaultConnectionProxy() # 函數(shù) # 重置查詢記錄緩存 def reset_queries(**kwargs): pass # 關(guān)閉不可用或超時(如果有設(shè)置 CONN_MAX_AGE)連接 def close_old_connections(**kwargs): pass # 信號 # 在請求開始或完成時自動調(diào)用相應(yīng)處理函數(shù) signals.request_started.connect(reset_queries) signals.request_started.connect(close_old_connections) signals.request_finished.connect(close_old_connections)
重點是connections和connection兩個實例
connections 是 ConnectionHandler類
connections.all()會給出一個列表,里面的元素為DatabaseWrapper類
ConnectionHandler內(nèi)置對象及連接管理:
def __init__(): self._connections = local() # 連接包裝類里的連接是根據(jù)配置情況使用相應(yīng)的連接 def __getitem__(self, alias): '''略''' db = self.databases[alias] backend = load_backend(db['ENGINE']) conn = backend.DatabaseWrapper(db, alias) setattr(self._connections, alias, conn) # 返回所管理的數(shù)據(jù)庫連接 # 管理方式:分?jǐn)?shù)據(jù)庫,線程管理連接 def all(self): return [self[alias] for alias in self] # 關(guān)閉所有數(shù)據(jù)庫連接 def close_all(self): for alias in self: try: connection = getattr(self._connections, alias) except AttributeError: continue connection.close()
threading.local 是一個全局變量,local的屬性是非線程共享的,也就是在每一個線程中都會有單獨一個數(shù)據(jù)庫連接實例創(chuàng)建,因為代理及包裝的原因,該連接實例為對應(yīng)backend里的連接(比如,pymysql.connections.Connection)。
在線程池的情況下,close_old_connections方法是不能將線程中的數(shù)據(jù)庫連接關(guān)閉的。
connection是DefaultConnectionProxy類的實例,實際是DatabaseWrapper的實例 (使用了pymysql庫:import pymysql; pymysql.install_as_MySQLdb) DefaultConnectionProxy–>DatabaseWrapper–>pymysql.connections.Connection(根據(jù)connections的處理調(diào)用相應(yīng)的數(shù)據(jù)庫連接包) connection有幾個關(guān)鍵方法和屬性 connection.connection = '被包裝的pymysql.connections.Connection實例` connection.close_at = None if max_age is None else time.time() + max_age # 設(shè)置的連接關(guān)閉時間 connection.connect()# 獲取連接 connection.cursor() # 獲取游標(biāo) connection.close()# 關(guān)閉連接
2. 將數(shù)據(jù)庫連接改造為長連接
max_age(CONN_MAX_AGE) 是可以在settings里面配置的。
由于多個服務(wù)共用一套配置, 所以考慮直接在程序里修改
全局變量
max_age = 7 * 3600
在線程內(nèi)開始時做下判斷:
if not db.connection.connection or db.connection.close_at < time.time(): db.connection.close() db.connection.connect() db.connection.close_at = time.time() + max_age print "A new conn creates !" else: print "Still old conn!"
這樣每個線程池中的線程會循環(huán)執(zhí)行任務(wù)并只使用同一個連接,并可以控制在自己需要的連接時長后更換連接。
針對線程池的情況,close_old_connections基本沒啥用處, 可以跳過該處理
django.db.close_old_connections = lambda **kwargs : None
以上這篇django 數(shù)據(jù)庫連接模塊解析及簡單長連接改造方法就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Python中的簡寫操作(for、if簡寫、匿名函數(shù))
這篇文章主要介紹了Python中的簡寫操作(for、if簡寫、匿名函數(shù)),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07Django利用AJAX技術(shù)實現(xiàn)博文實時搜索
這篇文章主要介紹了Django如何利用AJAX技術(shù)實現(xiàn)博文實時搜索,幫助大家更好的理解和學(xué)習(xí)使用Django框架,感興趣的朋友可以了解下2021-05-05淺析Python中g(shù)lobal和nonlocal關(guān)鍵字的妙用
這篇文章主要來和大家一起深入探討Python中關(guān)鍵詞global和nonlocal的用法,包括詳細(xì)的示例代碼和實際應(yīng)用場景,感興趣的可以了解下2024-04-04詳解python定時簡單爬取網(wǎng)頁新聞存入數(shù)據(jù)庫并發(fā)送郵件
這篇文章主要介紹了python定時簡單爬取網(wǎng)頁新聞存入數(shù)據(jù)庫并發(fā)送郵件,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11Python爬取奶茶店數(shù)據(jù)分析哪家最好喝以及性價比
這篇文章主要介紹了用Python告訴你奶茶哪家最好喝性價比最高,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-09-09