Python 数据库连接池
python编程中可以使用pymysql进行数据库连接及增删改查操作,但每次连接mysql请求时,都是独立的去请求访问,比较浪费资源,而且访问数量达到一定数量时,对mysql的性能会产生较大的影响。因此实际使用中,通常会使用数据库的连接池技术,来访问数据库达到资源复用。
python的数据库连接池包:DBUtils
DBUtils提供两种外部接口:
PersistentDB:提供线程专用的数据库连接,并自动管理连接。
PooledDB:提供线程间可共享的数据库连接,并自动管理连接。?
DBUtils包安装: pip3 install DBUtils或者下载 DBUtils 安装包,解压后,使用python setup.py install 命令进行安装。
未使用连接池的数据库方法:
def?getconn(host,?user,?passwd,?db,?sql,?port=3306,charset='utf8'): ????conn?=?pymysql.connect(host=host,?user=user,?passwd=passwd,?port=port,?db=db,?charset=charset)??#建立连接 ????cur?=?conn.cursor(cursor=pymysql.cursors.DictCursor)????????#建立游标并指定游标类型 ????cur.execute(sql)??????????????????????????????#执行sql ????if?sql.startswith('select'):????????????????????#判断sql是否是select ????????res?=?cur.fetchone() ????else: ????????conn.commit()???????????????????#insert\delete\update语句执行完毕后需要进行commit ????????res?=?88 ????cur.close()????????????????????????#关闭游标 ????conn.close()???????????????????????#关闭连接 ????return?res
用数据库连接池后的方法:
import?MySQLdb from?DBUtils.PooledDB?import?PooledDB pool?=?PooledDB(MySQLdb,5,host='localhost',user='root',passwd='pwd',db='myDB',port=3306)?#5为连接池里的最少连接数 ? conn?=?pool.connection()??#以后每次需要数据库连接就是用connection()函数获取连接就好了 cur=conn.cursor() SQL="select?*?from?table1" r=cur.execute(SQL) r=cur.fetchall() cur.close() conn.close()
下面利用pymysql 和 DBUtils 建立自己的mysql数据库连接工具包。
class?OPMysql(object): ????__pool?=?None ????def?__init__(self): ????????#?构造函数,创建数据库连接、游标 ????????self.coon?=?OPMysql.getmysqlconn() ????????self.cur?=?self.coon.cursor(cursor=pymysql.cursors.DictCursor) ????#?数据库连接池连接 ????@staticmethod ????def?getmysqlconn(): ????????if?OPMysql.__pool?is?None: ????????????__pool?=?PooledDB(creator=pymysql,?mincached=1,?maxcached=20,?host=mysqlInfo['host'],?user=mysqlInfo['user'],?passwd=mysqlInfo['passwd'],?db=mysqlInfo['db'],?port=mysqlInfo['port'],?charset=mysqlInfo['charset']) ????????????print(__pool) ????????return?__pool.connection() ????#?插入\更新\删除sql ????def?op_insert(self,?sql): ????????print('op_insert',?sql) ????????insert_num?=?self.cur.execute(sql) ????????print('mysql?sucess?',?insert_num) ????????self.coon.commit() ????????return?insert_num ????#?查询 ????def?op_select(self,?sql): ????????print('op_select',?sql) ????????self.cur.execute(sql)??#?执行sql ????????select_res?=?self.cur.fetchone()??#?返回结果为字典 ????????print('op_select',?select_res) ????????return?select_res ????#释放资源 ????def?dispose(self): ????????self.coon.close() ????????self.cur.close()
配置文件mysqlinfo,包含数据库的连接信息、用户名密码等:
mysqlInfo?=?{ ????"host":?'192.168.1.112', ????"user":?'root', ????"passwd":?'123456', ????"db":?'apitest', ????"port":?3306, ????"charset":?'utf8' }
创建test,测试数据库连接
if?__name__?==?'__main__': ????#申请资源 ????opm?=?OPMysql() ????sql?=?"select?*?from?demo?where?name?='a'?and?pwd='e10adc3949ba59abbe56e057f20f883e'?" ????res?=?opm.op_select(sql) ????#释放资源 ????opm.dispose()
PooledDB参数解释:
mincached,最少的空闲连接数,如果空闲连接数小于这个数,pool会创建一个新的连接。
maxcached,空闲连接数,如果空闲连接数大于这个数,pool会关闭空闲连接。
maxconnections,连接数,进程中可创建的线程数。
blocking, 当连接数达到连接数时,再次请求时,如果这个值是True,请求连接的程序会一直等待,直到当前连接数小于连接数;如果这个值为False,会报错。
masxshared,当连接数达到这个数时,新请求的连接会分享已经分配出去的连接。
在uwsgi中,每个http请求都会有一个进程,连接池中配置的连接数都是一个进程为单位的(即上面的连接数,都是在一个进程中创建的线程数),如果业务中,一个http请求中需要的sql连接数不是很多的话(其实大多数都只需要创建一个连接),配置的连接数配置都不需要太大。
连接池对性能的提升:
在程序创建连接的时候,可以从一个空闲的连接中获取,不需要重新初始化连接,提升获取连接的速度。
关闭连接的时候,把连接放回连接池,而不是真正的关闭,所以可以减少频繁的打开和关闭连接。