python的數據庫連接池實現----DBUtils
DBUtils 屬於WebWare項目的數據庫連接池實現模塊,用於對數據庫連接線程化,使可以安全和有效的訪問數據庫的模塊
全局的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 module from DBUtils.PersistentDB import PersistentDB persist = 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 module from DBUtils.PooledDB import PooledDB pool = 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 cur db.close() # or del db