python的数据库连接池实现----DBUtils
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模块的依赖如下图所示:
对典型的PyGreSQL模块依赖如下图所示:
SimplePooledDB
DBUtils.SimplePooledDB 是一个非常简单的数据库连接池实现。他比完善的 PooledDB 模块缺少很多功能。 DBUtils.SimplePooledDB 本质上类似于 MiscUtils.DBPool
SteadyDB
DBUtils.SteadyDB
一个典型的例子是数据库重启时,而你的程序仍然在运行并需要访问数据库,或者当你的程序连接了一个防火墙后面的远程数据库,而防火墙重启时丢失了状态时。
一般来说你不需要直接使用 SteadyDB 它只是给接下来的两个模块提供基本服务, PersistentDB 和 PooledDB
PersistentDB
DBUtils.PersistentDB 实现了强硬的、线程安全的、顽固的数据库连接,使用DB-API 2模块。如下图展示了使用 PersistentDB
当一个线程首次打开一个数据库连接时,一个连接会打开并仅供这个线程使用。当线程关闭连接时,连接仍然持续打开供这个线程下次请求时使用这个已经打开的连接。连接在线程死亡时自动关闭。
简单的来说 PersistentDB
因此, PersistentDB
PooledDB
DBUtils.PooledDB 实现了一个强硬的、线程安全的、有缓存的、可复用的数据库连接,使用任何DB-API 2模块。如下图展示了使用 PooledDB
如图所示 PooledDB 可以在不同线程之间共享打开的数据库连接。这在你连接并指定 maxshared 参数,并且底层的DB-API 2接口是线程安全才可以,但是你仍然可以使用专用数据库连接而不在线程之间共享连接。除了共享连接以外,还可以设立一个至少 mincached 的连接池,并且最多允许使用 maxcached
如果底层DB-API模块是非线程安全的,线程锁会确保使用 PooledDB
该选择哪一个?
PersistentDB 和 PooledDB
所以选择何种模块,可以参考上面的解释。 PersistentDB 将会保持一定数量的连接供频繁使用。在这种情况下你总是保持固定数量的连接。如果你的程序频繁的启动和关闭线程,最好使用 PooledDB
当然,这两个模块的接口是很相似的,你可以方便的在他们之间转换,并查看哪个更好一些。
使用方法
所有模块的使用方法都很相似,但是在初始化 "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
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
举个例子,如果你正在使用 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 = 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