1. 程式人生 > 程式設計 >django 資料庫連線模組解析及簡單長連線改造方法

django 資料庫連線模組解析及簡單長連線改造方法

工作中純服務端的專案用到了執行緒池和django的ORM部分。django 的資料庫連線在每一個執行緒中開啟一份,並在查詢完畢後自動關閉連線。

執行緒池處理任務時,正常使用的連線中不會被關閉,但由於資料庫端有最長連線時間的限制(預設為8小時),在超時後會發生InterfaceError: (0,'')(連線關閉後使用連線/遊標)或Error(2006,'MySQL server has gone away')(mysql 伺服器主動關閉連線)這類錯誤,所以一般會在每個任務執行緒中呼叫django.db.connection.close()進行關閉操作。

但對於頻繁進行資料庫連線並操作資料庫的業務,反覆建立連線並不是好的選擇,這種場景下可以考慮將連線改造為長連線。

1. django 程式碼的閱讀筆記

django.db.__init__.py 
#物件:
connections = ConnectionHandler()
connection = DefaultConnectionProxy()
# 函式
# 重置查詢記錄快取
def reset_queries(**kwargs):
 pass
# 關閉不可用或超時(如果有設定 CONN_MAX_AGE)連線
def close_old_connections(**kwargs):
 pass
# 訊號
# 在請求開始或完成時自動呼叫相應處理函式
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內建物件及連線管理:

def __init__():
 self._connections = local()

# 連線包裝類裡的連線是根據配置情況使用相應的連線
def __getitem__(self,alias):
 '''略'''
 db = self.databases[alias]
 backend = load_backend(db['ENGINE'])
 conn = backend.DatabaseWrapper(db,alias)
 setattr(self._connections,alias,conn)

# 返回所管理的資料庫連線
# 管理方式:分資料庫,執行緒管理連線 
def all(self):
 return [self[alias] for alias in self]

# 關閉所有資料庫連線
def close_all(self):
 for alias in self:
  try:
   connection = getattr(self._connections,alias)
  except AttributeError:
   continue
  connection.close()

threading.local 是一個全域性變數,local的屬性是非執行緒共享的,也就是在每一個執行緒中都會有單獨一個數據庫連線例項建立,因為代理及包裝的原因,該連線例項為對應backend裡的連線(比如,pymysql.connections.Connection)。

線上程池的情況下,close_old_connections方法是不能將執行緒中的資料庫連線關閉的。

connection是DefaultConnectionProxy類的例項,實際是DatabaseWrapper的例項 
(使用了pymysql庫:import pymysql; pymysql.install_as_MySQLdb) 
DefaultConnectionProxy–>DatabaseWrapper–>pymysql.connections.Connection(根據connections的處理呼叫相應的資料庫連線包) 
connection有幾個關鍵方法和屬性

connection.connection = '被包裝的pymysql.connections.Connection例項`
connection.close_at = None if max_age is None else time.time() + max_age # 設定的連線關閉時間

connection.connect()# 獲取連線
connection.cursor() # 獲取遊標
connection.close()# 關閉連線

2. 將資料庫連線改造為長連線

max_age(CONN_MAX_AGE) 是可以在settings裡面配置的。

由於多個服務共用一套配置, 所以考慮直接在程式裡修改

全域性變數

max_age = 7 * 3600 

線上程內開始時做下判斷:

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!"

這樣每個執行緒池中的執行緒會迴圈執行任務並只使用同一個連線,並可以控制在自己需要的連線時長後更換連線。

針對執行緒池的情況,close_old_connections基本沒啥用處,可以跳過該處理

django.db.close_old_connections = lambda **kwargs : None

以上這篇django 資料庫連線模組解析及簡單長連線改造方法就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。