python數據庫鏈接工具DBUtils

DBUtils是一個容許在多線程python應用和數據庫之間安全及高效鏈接的python模塊套件。python

模塊

DBUtils套件包含兩個模塊子集,一個適用於兼容DB-API 2接口的模塊,一個適用於PyGreSQL的模塊。mysql

  • Universal DB-API 2 variant
    圖片描述

    該子集下的模塊依賴關係如圖:
    圖片描述sql

  • Classic PyGreSQL variant
    圖片描述

    該子集下的模塊依賴關係如圖:
    圖片描述數據庫

SimplePooledDB

DBUtils.SimplePooledDB是池化數據庫鏈接中很是基礎的一種實現。相較於PooledDB,它並不那麼複雜,且缺乏failover機制。SimplePooledDB應視爲一種概念演示,不要直接在生產環境使用。緩存

SteadyDB

DBUtils.SteadyDB基於兼容DB-API 2接口的數據庫模塊建立的普通鏈接,實現了"增強"鏈接。具體指當數據庫鏈接關閉、丟失或使用頻率超出限制時,將自動從新獲取鏈接。安全

典型的應用場景以下:在某個維持了某些數據庫鏈接的程序運行時重啓了數據庫,或在某個防火牆隔離的網絡中訪問遠程數據庫時重啓了防火牆。網絡

PersistentDB

DBUtils.PersistentDB實現了穩定,線程仿射(thread-affine),持久化的數據庫鏈接。下圖顯式了使用PersistentDB進行鏈接時涉及的鏈接層:
圖片描述session

某個線程第一次開啓一個數據庫鏈接時,該鏈接將用於此特定線程。即便在線程中關閉鏈接,鏈接也會保持打開狀態,以便同一個線程的下一次鏈接請求直接使用。線程結束時該鏈接會自動關閉。多線程

簡而言之:PersistentDB會回收數據庫鏈接從而在總體上增長多線程應用的數據庫訪問性能,它確保線程之間永遠不會共享鏈接。框架

所以即便底層的DB-API模塊不是connection級別的線程安全,PersistentDB也能夠完美實現線程安全,避免在其餘線程更改數據庫會話或執行跨多個SQL指令的事務時出現問題。


要使用PersistentDB模塊,首先傳遞如下參數建立PersistentDB實例:

  • creator:兼容DB-API 2的數據庫模塊或返回DB-API 2鏈接的任意函數
  • maxusage:單個鏈接的最大重用次數(0或None表示無重用次數限制),達到該限制後自動關閉並從新打開鏈接
  • setsession:設置鏈接會話的sql指令列表,好比["set wait_timeout = 100", ...]
  • failures:異常類或異常類元組。在默認的(OperationalError, InternalError)不能處理鏈接failover機制時使用
  • ping:若是ping()方法可用,該值表示什麼時候使用ping()方法檢查鏈接(0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always, and all other bit combinations of these values)
  • closeable:若是設置爲True,將容許手動close()鏈接,默認爲False,忽略關閉鏈接的操做,只在線程終止時自動關閉
  • threadlocal:表示thread-local數據的類。設置值爲threading.local可能獲取鏈接的速度更快,但不必定適用於全部狀況(例如,mod_wsgi會清空requests之間的threading.local數據)
  • 傳遞給creator參數值建立connection對象的參數,如host, database等
import pymysql
from DBUtils.PersistentDB import PersistentDB

persist = PersistentDB(creator=pymysql, user="root", passwd="123456", db="test")
# conn的使用和常規DB-API 2接口相似
conn = persist.connection()

NOTE:須要在鏈接上調用begin()方法明確開啓事務。這能夠確保a.只在事務完成時才從新打開鏈接b.鏈接被同一個線程重用時回滾。

PooledDB

DBUtils.PooledDB實現了穩定、線程安全的緩存鏈接池。下圖顯式了使用PooledDB進行鏈接時涉及的鏈接層:
圖片描述

使用正整數的maxshared參數和connection級別的線程安全的creator參數建立鏈接池時,鏈接池中的鏈接默認是線程間共享的。但仍能夠請求非線程共享的專用數據庫鏈接。

除了共享鏈接池外,還能夠建立至少mincached個,至多maxcached個鏈接的空閒鏈接池,在共享鏈接池未滿(不太理解)或線程請求專用數據庫鏈接時使用。當某個線程關閉再也不共享的鏈接時,該鏈接將回收到空閒鏈接池以便再次使用。

若是底層的DB-API 2模塊非線程安全,將使用線程鎖確保PooledDB鏈接是線程安全的。但對於線程專用的鏈接,要當心更改數據庫會話或執行跨多個SQL指令的事務帶來的不良影響。


要使用PoolDB模塊,首先傳遞如下參數建立PoolDB實例:

  • creator:同PersistentDB
  • mincached:鏈接池中空閒鏈接的初始數量(0表示不建立初始空閒鏈接)
  • maxcached:鏈接池中容許的最大空閒鏈接數(0或None表示無限制)
  • maxshared:容許的最大共享鏈接數(0或None表示全部鏈接都是專用的),When this maximum number is reached, connections are shared if they have been requested as shareable
  • maxconnections:容許的最大鏈接數(0或None表示無限制)
  • blocking:查過最大值是否阻塞。True表示將阻塞直到釋放新的鏈接,默認False表示拋出異常
  • maxusage:同PersistentDB
  • setsession:同PersistentDB
  • reset:返回鏈接池時應該怎樣重置鏈接(False或None將只回滾明確調用了begin()開啓的事務,默認值爲True,出於安全考慮老是會回滾)
  • failures:同PersistentDB
  • ping:同PersistentDB
  • 傳遞給creator參數值建立connection對象的參數,如host, database等
import pymysql
from DBUtils.PooledDB import PooledDB

pool = PooledDB(creator=pymysql, 5, user="root", passwd="123456", db="test")
# conn的使用和常規DB-API 2接口相似
conn = pool.connection()

對於線程共享的鏈接池,能夠用如下方式獲取線程專用鏈接:

conn = pool.connection(shareable=False)
# 或者
conn = pool.dedicated_connection()

對於再也不使用的鏈接,調用close()方法回收到鏈接池。

在多線程環境中,不要寫如下代碼,這會致使鏈接過早釋放並被其餘線程重用,若是鏈接非線程安全可能致使程序出現嚴重錯誤:

pool.connection().cursor().execute(...)

NOTE:須要在鏈接上調用begin()方法明確開啓事務。這能夠確保a.只在事務完成時才從新打開鏈接b.鏈接在返回鏈接池以前執行回滾c.鏈接不會被其餘線程共享

如何選擇

PooledDB和PersistentDB都經過回收數據庫鏈接,且即便數據庫鏈接中斷也能保持穩定性的方式從而達到提高數據庫訪問性能的目的。在現實場景中應該如何選擇呢?對於保持常量線程數且頻繁使用數據庫的應用,使用PersistentDB;對於頻繁開啓、結束線程的應用,使用PooledDB。

其餘

若是程序中使用了ORM框架,如SQLObjectSQLAlchemy,不須要使用DBUtils,由於這些框架自身維護了鏈接池。

數據庫線程安全級別:
圖片描述
好比pymysql就是能夠共享模塊但不能共享鏈接,查看方式pymysql.threadsafety

相關文章
相關標籤/搜索