標籤:style http 使用 os io 資料 for ar
python的資料庫連接池實現----DBUtils
DBUtils 屬於WebWare項目的資料庫連接池實現模組,用於對資料庫連接線程化,使可以安全和有效訪問資料庫的模組
DBUtils實際上是一個包含兩個子模組的Python包,一個用於串連DB-API 2模組,另一個用於串連典型的PyGreSQL模組。
全域的DB-API 2變數 |
SteadyDB.py |
用於穩定資料庫連接 |
PooledDB.py |
串連池 |
PersistentDB.py |
維持持續的資料庫連接 |
SimplePooledDB.py |
簡單串連池 |
典型的 PyGreSQL 變數 |
SteadyPg.py |
穩定PyGreSQL串連 |
PooledPg.py |
PyGreSQL串連池 |
PersistentPg.py |
維持持續的PyGreSQL串連 |
SimplePooledPg.py |
簡單的PyGreSQL串連池 |
對標準DB-API 2模組的依賴如所示:
對典型的PyGreSQL模組依賴如所示:
SimplePooledDB
DBUtils.SimplePooledDB 是一個非常簡單的資料庫連接池實現。他比完善的 PooledDB 模組缺少很多功能。 DBUtils.SimplePooledDB 本質上類似於 MiscUtils.DBPool 這個Webware的組成部分。你可以把它看作一種示範程式。
SteadyDB
DBUtils.SteadyDB 是一個模組實現了"強硬"的資料庫連接,基於DB-API 2建立的原始串連。一個"強硬"的串連意味著在串連關閉之後,或者使用次數操作限制時會重新串連。
一個典型的例子是資料庫重啟時,而你的程式仍然在運行並需要訪問資料庫,或者當你的程式串連了一個防火牆後面的遠端資料庫,而防火牆重啟時丟失了狀態時。
一般來說你不需要直接使用 SteadyDB 它只是給接下來的兩個模組提供基本服務, PersistentDB 和 PooledDB 。
PersistentDB
DBUtils.PersistentDB 實現了強硬的、安全執行緒的、頑固的資料庫連接,使用DB-API 2模組。如展示了使用 PersistentDB 時的串連層步驟:
當一個線程首次開啟一個資料庫連接時,一個串連會開啟並僅供這個線程使用。當線程關閉串連時,串連仍然持續開啟供這個線程下次請求時使用這個已經開啟的串連。串連線上程死亡時自動關閉。
簡單的來說 PersistentDB 嘗試重用資料庫連接來提高線程化程式的資料庫訪問效能,並且他確保串連不會被線程之間共用。
因此, PersistentDB 可以在底層DB-API模組並非安全執行緒的時候同樣工作的很好,並且他會在其他線程改變資料庫會話或者使用多語句事務時同樣避免問題的發生。
PooledDB
DBUtils.PooledDB 實現了一個強硬的、安全執行緒的、有緩衝的、可複用的資料庫連接,使用任何DB-API 2模組。如展示了使用 PooledDB 時的工作流程:
PooledDB 可以在不同線程之間共用開啟的資料庫連接。這在你串連並指定 maxshared 參數,並且底層的DB-API 2介面是安全執行緒才可以,但是你仍然可以使用專用資料庫連接而不線上程之間共用串連。除了共用串連以外,還可以設立一個至少 mincached 的串連池,並且最多允許使用 maxcached 個串連,這可以同時用於專用和共用串連池。當一個線程關閉了一個非共用串連,則會返還到空閑串連池中等待下次使用。
如果底層DB-API模組是非安全執行緒的,線程鎖會確保使用 PooledDB 是安全執行緒的。所以你並不需要為此擔心,但是你在使用專用連線來改變資料庫會話或執行多命令事務時必須小心。
該選擇哪一個?
PersistentDB 和 PooledDB 都是為了重用資料庫連接來提高效能,並保持資料庫的穩定性。
所以選擇何種模組,可以參考上面的解釋。 PersistentDB 將會保持一定數量的串連供頻繁使用。在這種情況下你總是保持固定數量的串連。如果你的程式頻繁的啟動和關閉線程,最好使用 PooledDB 。後面將會提到更好的調整,尤其在使用安全執行緒的DB-API 2模組時。
當然,這兩個模組的介面是很相似的,你可以方便的在他們之間轉換,並查看哪個更好一些。
使用方法
所有模組的使用方法都很相似,但是在初始化 "Pooled" 和 "Persistent" 時還有有些不同,尤其是DB-API和PyGreSQL之間。
這裡只講解 PersistentDB 和更複雜的 PooledDB 模組。其他模組的細節請參與其文檔。使用Python解譯器控制台,你可以顯示 PooledDB 的文檔,如下:
help(PooledDB)
PersistentDB
為了使用 PersistentDB 你首先需要通過建立 PersistentDB 的執行個體來設定一個特定資料庫連接的產生器,床底如下參數:
- creator: 可以使用任意返回 DB-API 2 連線物件的函數活 DB-API 2 相容的資料庫模組。
- maxusage: 一個串連最大允許複用次數(預設為 0 或 False 意味著無限制的重用),當達到限制時,將會重新串連資料庫
- setsession: 一個可選的SQL命令列表可以用於準備會話,如 ["set datestyle to german", ...]
- creator 函數或產生 DB-API 2 串連的函數,可以接受這裡的附加參數,比如主機名稱、資料庫、使用者名稱、密碼等等。你也可以選擇傳遞給 creator 的其他參數,並允許提供失敗重連和負載平衡。
舉個例子,如果你正在使用 pgdb 作為資料庫模組並想要串連本機資料庫 mydb ,允許重用1000次:
import pgdb # import used DB-API 2 modulefrom DBUtils.PersistentDB import PersistentDBpersist = PersistentDB(pgdb, 1000, database=‘mydb‘)
按照如上設定完成了串連產生器之後,你可以按照如下來請求一個串連:
db = persist.connection()
你可以使用這些串連就像使用原始的DB-API 2串連一樣。實際上你得到的是一個通過``SteadyDB``得到的強硬的串連,基於DB-API 2。
關閉一個強硬的串連使用 db.close() ,這在內部實際上被忽略掉了,並且供下次使用。線上程關閉時,也會自動關閉資料庫連接。你可以改變這個行為通過 persist._closeable 為 True 。
PooledDB
為了使用 PooledDB 模組,你首先需要通過建立 PooledDB 來設定資料庫連接池,傳遞如下參數:
- creator: 可以產生 DB-API 2 串連的任何函數或 DB-API 2 相容的資料庫連接模組。
- mincached : 啟動時開啟的空串連數量(預設值 0 意味著開始時不建立串連)
- maxcached: 串連池使用的最多串連數量(預設值 0 代表不限制串連池大小)
- maxshared: 最大允許的共用串連數量(預設值 0 代表所有串連都是專用的)如果達到了最大數量,被請求為共用的串連將會被共用使用。
- maxconnections: 最大允許串連數量(預設值 0 代表不限制)
- blocking: 設定在達到最大數量時的行為(預設值 0 或 False 代表返回一個錯誤;其他代表阻塞直到串連數減少)
- maxusage: 單個串連的最大允許複用次數(預設值 0 或 False 代表不限制的複用)。當達到最大數值時,串連會自動重新串連(關閉和重新開啟)
- setsession: 一個可選的SQL命令列表用於準備每個會話,如 ["set datestyle to german", ...]
- creator 函數或可以產生串連的函數可以接受這裡傳入的其他參數,例如主機名稱、資料庫、使用者名稱、密碼等。你還可以選擇傳入creator函數的其他參數,允許失敗重連和負載平衡。
舉個例子,如果你正在使用 pgdb 作為DB-API模組,並希望串連池中至少有5個串連到資料庫 mydb
import pgdb # import used DB-API 2 modulefrom DBUtils.PooledDB import PooledDBpool = PooledDB(pgdb, 5, database=‘mydb‘)
一旦設定好了串連池,你就可以按照如下請求一個串連:
db = pool.connection()
你可以使用這些串連有如原始的DB-API 2一樣。而實際使用的是``SteadyDB``版本的強硬串連。
請注意串連可以與其他線程共用,只要你設定 maxshared 參數為非零,並且DB-API 2模組也允許。如果你想要使用專用連線則使用:
db = pool.connection(0)
如果你不再需要這個串連了,則可以返回給串連池使用 db.close() 。你也可以使用相同的方法擷取另一個串連。
警告: 在一個多線程環境,不要使用下面的方法:
pool.connection().cursor().execute(...)
這將會導致過早的釋放串連以供複用,而且如果是非安全執行緒還會出錯。確保連線物件在你的使用過程中是一直存在的,例如:
db = pool.connection()cur = db.cursor()cur.execute(...)res = cur.fetchone()cur.close() # or del curdb.close() # or del db