DBUtil内部实现过程解读
python数据库连接工具DBUtils
模块
DBUtils套件包含两个模块子集,一个适用于兼容DB-API 2接口的模块,一个适用于PyGreSQL的模块。
- Universal DB-API 2 variant
该子集下的模块依赖关系如图:
- Classic PyGreSQL variant
该子集下的模块依赖关系如图:
SimplePooledDB
DBUtils.SimplePooledDB是池化数据库连接中非常基础的一种实现。相较于PooledDB,它并不那么复杂,且缺少failover机制。SimplePooledDB应视为一种概念演示,不要直接在生产环境使用。
SteadyDB
DBUtils.SteadyDB基于兼容DB-API 2接口的数据库模块创建的普通连接,实现了"加强"连接。具体指当数据库连接关闭、丢失或使用频率超出限制时,将自动重新获取连接。
典型的应用场景如下:在某个维持了某些数据库连接的程序运行时重启了数据库,或在某个防火墙隔离的网络中访问远程数据库时重启了防火墙。
PersistentDB
DBUtils.PersistentDB实现了稳定,线程仿射(thread-affine),持久化的数据库连接。下图显式了使用PersistentDB进行连接时涉及的连接层:
某个线程第一次开启一个数据库连接时,该连接将用于此特定线程。即使在线程中关闭连接,连接也会保持打开状态,以便同一个线程的下一次连接请求直接使用。线程结束时该连接会自动关闭。
简而言之: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框架,如SQLObject或SQLAlchemy,不需要使用DBUtils,因为这些框架自身维护了连接池。
数据库线程安全级别:
比如pymysql就是可以共享模块但不能共享连接,查看方式pymysql.threadsafety
DBUtil内部实现过程解读的更多相关文章
- 【教程】手把手教你如何利用工具(IE9的F12)去分析模拟登陆网站(百度首页)的内部逻辑过程
[前提] 想要实现使用某种语言,比如Python,C#等,去实现模拟登陆网站的话,首先要做的事情就是使用某种工具,去分析本身使用浏览器去登陆网页的时候,其内部的执行过程,内部逻辑. 此登陆的逻辑过程, ...
- CLRMonitor - 跟踪CLR内部执行过程工具
CLRMonitor v1.0.1511.13 点击此处下载 软件介绍:这款软件主要用于跟踪CLR内部执行过程,定位当前程序执行的命名空间以及方法名等信息.可以迅速找到被跟踪程序的当前执行方法名.本软 ...
- 【Spring-web】RestTemplate源码学习——梳理内部实现过程
2016-12-28 by 安静的下雪天 http://www.cnblogs.com/quiet-snowy-day/p/6228198.html 提示:使用手机浏览时请注意,图多费流量. 本篇 ...
- ORACLE之SQL语句内部解析过程【weber出品】
一.客户端通过监听连接到数据库,数据库开启一个server process进程来接收客户端传过来的sql. 1.这条sql语句从来都没有被执行过.(硬解析) 2.这条sql语句被执行过.(软解析) 二 ...
- STM32启动过程解读与跟踪验证
经过查阅各种官方文献和对代码进行单步跟踪,详细地叙述了STM32加电启动的具体过程.对于关键性的语句都指明了出处.下面将学习成果分享给大家,由于笔者知识有限,不当之处敬请指出. 为了更好的说明问题,先 ...
- HttpApplication 对象的创建过程及HttpModule过滤器的内部实现过程
最近通过Reflector学习了一下asp.net内部的原理,做做笔记,方便以后查阅. 先看下HttpApplication 对象的创建过程 从IHttpHandler applicationInst ...
- 当程序执行一条查询语句时,MySQL内部到底发生了什么? (说一下 MySQL 执行一条查询语句的内部执行过程?
先来个最基本的总结阐述,希望各位小伙伴认真的读一下,哈哈: 1)客户端(运行程序)先通过连接器连接到MySql服务器. 2)连接器通过数据库权限身份验证后,会先查询数据库缓存是否存在(之前执行过相同条 ...
- Struts2内部执行过程
首先是Struts2的流程图. 一.当有一个请求的时候.执行以下流程. 1 客户端初始化一个指向Servlet容器的请求: 2 这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做Act ...
- mysql系列二、mysql内部执行过程
向MySQL发送一个请求的时候,MySQL到底做了什么 客户端发送一条查询给服务器. 服务器先检查查询缓存,如果命中了缓存,则立刻返回存储在缓存中的结果.否则进入下一阶段. 服务器端进行SQL解析.预 ...
随机推荐
- redis高可用之sentinel哨兵
一,单实例模式 当系统中只有一台redis运行时,一旦该redis挂了,会导致整个系统无法运行. 二,主从模式 由于单台redis出现单点故障,就会导致整个系统不可用,所以想到的办法自然就是备份.当一 ...
- java基础(5)---内存分配
一.内存分配 如: 先写下面的源代码: 如果继续写:
- [转]BIO/NIO/AIO的几个思考
原文:https://www.jianshu.com/p/ff29e028af07 ----------------------------------------------------- BIO/ ...
- seo与python大数据结合给文本分词并提取高频词
最近研究seo和python如何结合,参考网上的一些资料,写的这个程序. 目的:分析某个行业(例如:圆柱模板)用户最关心的一些词,根据需求去自动调整TDK,以及栏目,内容页的规划 使用方法: 1.下载 ...
- python 'NoneType' object has no attribute 'get'
获取 页面链接的时候报错 'NoneType' object has no attribute 'get' href = div.find("a").get("href& ...
- 第113题:路径总和II
一. 问题描述 给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径. 说明: 叶子节点是指没有子节点的节点. 示例: 给定如下二叉树,以及目标和 sum = 22, 5 ...
- 杭电2019多校第八场 Acesrc and Good Numbers——思维打表&&oeis
题意 给定 $d,x$,$f(d,k)$ 表示 $1 \sim k$ 中 $d$ 出现的次数, $k$ 满足 $f(d,k) = k$,求小于 $x$ 的最大的 $k$. 分析 正解不会...,学习了 ...
- Airtest真机链接(一)
确认ADB是否能够正常连接到手机 windows系统下: 用USB线连好手机后,进入AirtestIDE文件夹,在 AirtestIDE_2019-05-09_py3_win64/airtest/co ...
- 使用jQuery快速高效制作网页交互特效---JavaScript对象及初始面向对象
一.JavaScript中的基本数据类型 number(数值类型) string(字符串类型) boolean(布尔类型) null(空类型) undefined(未定义类型) ...
- Neo4j 快速清除数据库数据
在开发过程中,很多时候需要快(简)速(单)清(粗)除(暴)Neo4j中存在的海量数据节点和关系数据.在这种情况下,delete和detach从性能上都已力不从心.Neo4j官方推荐清库方法,即删除gr ...