DBUtils是一个容许在多线程python应用和数据库之间安全及高效链接的python模块套件。python
DBUtils套件包含两个模块子集,一个适用于兼容DB-API 2接口的模块,一个适用于PyGreSQL的模块。mysql
该子集下的模块依赖关系如图:sql
该子集下的模块依赖关系如图:数据库
DBUtils.SimplePooledDB
是池化数据库链接中很是基础的一种实现。相较于PooledDB
,它并不那么复杂,且缺乏failover机制。SimplePooledDB应视为一种概念演示,不要直接在生产环境使用。缓存
DBUtils.SteadyDB
基于兼容DB-API 2接口的数据库模块建立的普通链接,实现了"增强"链接。具体指当数据库链接关闭、丢失或使用频率超出限制时,将自动从新获取链接。安全
典型的应用场景以下:在某个维持了某些数据库链接的程序运行时重启了数据库,或在某个防火墙隔离的网络中访问远程数据库时重启了防火墙。网络
DBUtils.PersistentDB
实现了稳定,线程仿射(thread-affine
),持久化的数据库链接。下图显式了使用PersistentDB进行链接时涉及的链接层:session
某个线程第一次开启一个数据库链接时,该链接将用于此特定线程。即便在线程中关闭链接,链接也会保持打开状态,以便同一个线程的下一次链接请求直接使用。线程结束时该链接会自动关闭。多线程
简而言之:PersistentDB会回收数据库链接从而在总体上增长多线程应用的数据库访问性能,它确保线程之间永远不会共享链接。框架
所以即便底层的DB-API模块不是connection级别的线程安全,PersistentDB也能够完美实现线程安全,避免在其余线程更改数据库会话或执行跨多个SQL指令的事务时出现问题。
要使用PersistentDB模块,首先传递如下参数建立PersistentDB实例:
(OperationalError, InternalError)
不能处理链接failover机制时使用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
)threading.local
可能获取链接的速度更快,但不必定适用于全部状况(例如,mod_wsgi
会清空requests之间的threading.local数据)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.链接被同一个线程重用时回滚。
DBUtils.PooledDB
实现了稳定、线程安全的缓存链接池。下图显式了使用PooledDB进行链接时涉及的链接层:
使用正整数的maxshared
参数和connection级别的线程安全的creator
参数建立链接池时,链接池中的链接默认是线程间共享的。但仍能够请求非线程共享的专用数据库链接。
除了共享链接池外,还能够建立至少mincached
个,至多maxcached
个链接的空闲链接池,在共享链接池未满(不太理解)或线程请求专用数据库链接时使用。当某个线程关闭再也不共享的链接时,该链接将回收到空闲链接池以便再次使用。
若是底层的DB-API 2模块非线程安全,将使用线程锁确保PooledDB链接是线程安全的。但对于线程专用的链接,要当心更改数据库会话或执行跨多个SQL指令的事务带来的不良影响。
要使用PoolDB模块,首先传递如下参数建立PoolDB实例:
When this maximum number is reached, connections are shared if they have been requested as shareable
begin()
开启的事务,默认值为True,出于安全考虑老是会回滚)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框架,如SQLObject
或SQLAlchemy
,不须要使用DBUtils,由于这些框架自身维护了链接池。
数据库线程安全级别:
好比pymysql
就是能够共享模块但不能共享链接,查看方式pymysql.threadsafety