全部博文(2065)
分类: Python/Ruby
2010-02-06 12:10:06
python数据库连接池专题
昨天测试了一下开500个线程去请求数据库,不过这个时间不清楚会耗多少。即同时发起这么多的线程其效率会如何。于是想到是不是用数据库连接池技术可以明显改善一下这样的连接操作呢。呆会整理完了之后要测试一个数据:频繁建立与关闭数据库连接的效率与连接池之间的性能对比!
一、DBUtils模块学习
DBUtils实际上是一个包含两个子模块的Python包,一个用于连接DB-API 2模块,另一个用于连接典型的PyGreSQL模块。
PS:个人感觉 连接DB-API 2模块是不是讲的就是连接类似于MYSQL这样的API呢
全局的DB-API 2变量 |
|
SteadyDB.py |
用于稳定数据库连接 |
PooledDB.py |
连接池 |
PersistentDB.py |
维持持续的数据库连接(持续性连接) |
SimplePooledDB.py |
简单连接池 |
PS:先摘抄DB-API出来一下吧
对标准DB-API
2模块的依赖如下图所示:
PS:从上图我们可以得知 如果用到了连接池与持久连接的话就需要用到稳定数据库连接。
安装
安装为顶层模块
python setup.py install
具体的模块学习:
DBUtils.SimplePooledDB 是一个非常简单的数据库连接池实现。他比完善的 PooledDB 模块缺少很多功能。 DBUtils.SimplePooledDB 本质上类似于 MiscUtils.DBPool 这个Webware的组成部分。你可以把它看作一种演示程序。
PS:从上图可以知道它是直接连接到DB-API的
DBUtils.SteadyDB 是一个模块实现了"强硬"的数据库连接,基于DB-API 2建立的原始连接。一个"强硬"的连接意味着在连接关闭之后,或者使用次数操作限制时会重新连接。一个典型的例子是数据库重启时,而你的程序仍然在运行并需要访问数据库,或者当你的程序连接了一个防火墙后面的远程数据库,而防火墙重启时丢失了状态时。
一般来说你不需要直接使用 SteadyDB 它只是给接下来的两个模块提供基本服务, PersistentDB 和 PooledDB 。
(PS:这个模块一般不面对用户的。而只是提供基础服务之用的!)
DBUtils.PersistentDB
实现了强硬的、线程安全的、顽固的数据库连接,使用DB-API 2模块。如下图展示了使用 PersistentDB 时的连接层步骤:
DBUtils.PooledDB 实现了一个强硬的、线程安全的、有缓存的、可复用的数据库连接,使用任何DB-API 2模块。如下图展示了使用 PooledDB 时的工作流程:
(这两个模块是建立在SteadyDB 之上)
目前供我们选择的有两个模块:
PersistentDB 和 PooledDB 都是为了重用数据库连接来提高性能,并保持数据库的稳定性。
所以选择何种模块,可以参考上面的解释。
PersistentDB 将会保持一定数量的连接供频繁使用。在这种情况下你总是保持固定数量的连接。如果你的程序频繁的启动和关闭线程,最好使用 PooledDB 。后面将会提到更好的调整,尤其在使用线程安全的DB-API 2模块时。
(两种连接池对象可以供选择!)
当然,这两个模块的接口是很相似的,你可以方便的在他们之间转换,并查看哪个更好一些。
为了使用 PersistentDB 你首先需要通过创建 PersistentDB 的实例来设置一个特定数据库连接的生成器,床底如下参数:
为了使用 PooledDB 模块,你首先需要通过创建 PooledDB 来设置数据库连接池,传递如下参数:
举个例子,如果你正在使用 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-API 2模块也允许。如果你想要使用专用连接则使用:
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
二、示例 [方便我将来直接使用]
2.1 使用PersistentDB 模块
import threading,time,datetime
import MySQLdb
import DBUtils.PersistentDB
persist =
DBUtils.PersistentDB.PersistentDB(MySQLdb,100,host='localhost',user='root',passwd='321',db='test',charset='utf8')
conn = persist.connection()
cursor = conn.cursor()
cursor.execute("insert into me values(1,'22222')")
conn.commit()
conn.close()
就可以得到数据库连接了!
2.2 使用PooledDB 连接池
参数:
#-*-coding:utf-8-*-
import threading,time,datetime
import MySQLdb
from DBUtils import PooledDB
pool =
PooledDB.PooledDB(MySQLdb,10,50,100,500,False,host='localhost',user='root',passwd='321',db='test')
conn = pool.connection()
cursor = conn.cursor()
cursor.execute("insert into me values(1,'22222')")
conn.commit()
conn.close()
应用于多线程环境中使用!
示例:
#-*-coding:utf-8-*-
import threading,time,datetime
import MySQLdb
from DBUtils import PooledDB
pool =
PooledDB.PooledDB(MySQLdb,100,50,100,490,False,host='localhost',user='root',passwd='321',db='test',charset='utf8')
默认打开的时候就创建了100个数据库连接。检查发现果然数据库中有100个
class MyThread(threading.Thread):
def __init__(self,threadName):
self.conn = pool.connection() 直接从数据库连接池中提取
threading.Thread.__init__(self,name=threadName)
def run(self):
cursor=self.conn.cursor()
print "hello--->",self.getName()
file_objct = open('8.txt','a+')
file_objct.write(self.getName()+'\n')
file_objct.close()
#cursor.execute("call loaddate();")
#self.conn.commit()
time.sleep(10)
def __del__(self):
self.conn.close()
self.conn = None
for i in range(5):
obj = MyThread(str(i))
obj.start()
如果我现在将代码调整如下:
#-*-coding:utf-8-*-
import threading,time,datetime
import MySQLdb
from DBUtils import PooledDB
pool =
PooledDB.PooledDB(MySQLdb,100,50,100,400,False,host='localhost',user='root',passwd='321',db='test',charset='utf8')
class MyThread(threading.Thread):
def __init__(self,threadName):
self.conn = pool.connection()
threading.Thread.__init__(self,name=threadName)
def run(self):
cursor=self.conn.cursor()
print "hello--->",self.getName()
file_objct = open('8.txt','a+')
file_objct.write(self.getName()+'\n')
file_objct.close()
#cursor.execute("call loaddate();")
#self.conn.commit()
time.sleep(10)
def __del__(self):
self.conn.close()
self.conn = None
for i in range(402):
obj = MyThread(str(i))
obj.start()
连接池最大的数目才 400 现在我想要创建 402个 肯定报错了!