Python數據庫鏈接池模塊-----DBUtils使用

python的數據庫鏈接池實現----DBUtilspython

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模塊的依賴以下圖所示:緩存

dbdep.gif

對典型的PyGreSQL模塊依賴以下圖所示:安全

pgdep.gif

SimplePooledDB

DBUtils.SimplePooledDB 是一個很是簡單的數據庫鏈接池實現。他比完善的 PooledDB 模塊缺乏不少功能。 DBUtils.SimplePooledDB 本質上相似於 MiscUtils.DBPool 這個Webware的組成部分。你能夠把它看做一種演示程序。session

SteadyDB

DBUtils.SteadyDB 是一個模塊實現了"強硬"的數據庫鏈接,基於DB-API 2創建的原始鏈接。一個"強硬"的鏈接意味着在鏈接關閉以後,或者使用次數操做限制時會從新鏈接。多線程

一個典型的例子是數據庫重啓時,而你的程序仍然在運行並須要訪問數據庫,或者當你的程序鏈接了一個防火牆後面的遠程數據庫,而防火牆重啓時丟失了狀態時。負載均衡

通常來講你不須要直接使用 SteadyDB 它只是給接下來的兩個模塊提供基本服務, PersistentDB 和 PooledDB 。函數

PersistentDB

DBUtils.PersistentDB 實現了強硬的、線程安全的、頑固的數據庫鏈接,使用DB-API 2模塊。以下圖展現了使用 PersistentDB 時的鏈接層步驟:性能

persist.gif

當一個線程首次打開一個數據庫鏈接時,一個鏈接會打開並僅供這個線程使用。當線程關閉鏈接時,鏈接仍然持續打開供這個線程下次請求時使用這個已經打開的鏈接。鏈接在線程死亡時自動關閉。fetch

簡單的來講 PersistentDB 嘗試重用數據庫鏈接來提升線程化程序的數據庫訪問性能,而且他確保鏈接不會被線程之間共享。

所以, PersistentDB 能夠在底層DB-API模塊並不是線程安全的時候一樣工做的很好,而且他會在其餘線程改變數據庫會話或者使用多語句事務時一樣避免問題的發生。

PooledDB

DBUtils.PooledDB 實現了一個強硬的、線程安全的、有緩存的、可複用的數據庫鏈接,使用任何DB-API 2模塊。以下圖展現了使用 PooledDB 時的工做流程:

pool.gif

如圖所示 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
相關文章
相關標籤/搜索