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

相关文章
相关标签/搜索