python巧妙使用数据库连接池PooledDB连接MySQL,操作性能比对

文摘   科技   2023-06-04 18:40   北京  


是我,是你


在李娟的《冬牧场》中有这样一句话:
“太阳未出时,全世界都像一个梦,唯有月亮是真实的;太阳出来后,全世界都真实了,唯有月亮像一个梦。”


环境:

Pycharm

Python 3.9.16



安装包:

pip install DBUtils==3.0.3

pip install PyMySQL==1.0.3




回顾上篇


python对PowerPoint(PPT)操作,自动生成PPT文档

九月de云,公众号:九月de云python对PowerPoint(PPT)的增、删、改和插入表格及图片操作,自动生成PPT文档



开始本篇


PooledDB是DBUtils中的一个模块,可以很方便轻松地创建数据库连接池。它可以管理多个数据库连接,并且可以重复使用已经建立的连接,从而减少建立连接的开销


以下一个简单的例子:

需要查询id为1的数据

# -*- coding: utf-8 -*-import pymysqlfrom dbutils.pooled_db import PooledDB
pool = PooledDB( creator=pymysql, maxconnections=3, mincached=2, maxcached=3, maxshared=3, reset=True, blocking=True, maxusage=0, ping=1, host='localhost', user='root',    password='111111',    database='test', charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor)# 从连接池中获取一个连接conn = pool.connection()cur = conn.cursor()# 执行SQL查询sql = 'SELECT * FROM users_msg WHERE id=%s'cur.execute(sql, (1,))result = cur.fetchone()print("查询结果为:", result)# 关闭并将连接归还到连接池cur.close()conn.close()# 关闭连接池pool.close()

结果:

查询结果为:{'id': 1, 'name': 'Nancy Hc', 'age': 26, 'score': 84.76}


其中参数的介绍:

creator: 数据库连接对象的构造函数

maxconnections: 连接池的最大连接数。如果设置为0或None,则没有限制

mincached: 初始化时连接池至少创建的空闲连接数量

maxcached: 连接池中允许的最大空闲连接数量。如果设置为0或None,则不会创建

maxshared: 共享连接数,即同时使用的最大数据库连接数(默认为0,表示不共享)

maxusage: 每个连接的最大使用次数,超过该次数则该连接将被关闭并从连接池中移除。如果设置为0或None,则连接池不会关闭连接

reset: 如果设置为True,则在将连接放回池中之前将其重置为其初始状态

blocking: 连接池中在没有可用的连接时,是否等待,如果设置为True,等待,直到有可用连接再分配;如果设置为False,不等待,达到最大连接数时再请求新的连接将抛出异常

failures: 在尝试获取连接时,数据库连接失败后可以尝试重新连接的次数。如果设置为None,则只会尝试一次

ping: 表示是否需要在使用数据库连接之前检查连接的连通性。如果设置为0,则不检查;如果设置为1,则在使用连接之前检查连通性;如果设置为大于1的整数,则会在分配连接之前尝试该次数的数据库连接

host: 表示数据库连接地址

user: 表示数据库连接用户名

password: 表示数据库连接密码

database: 表示数据库名

charset: 表示数据库字符集设置

cursorclass: 表示指定DictCursor(字典)作为游标类


提示

注意maxcached和maxconnections两个参数有所不同:

maxcached表示连接池中允许的最大空闲连接数量,而maxconnections表示连接池的最大连接数(包括活动和非活动连接)。如果您需要限制同时打开的连接数,请使用maxconnections参数,大家根据实际情况使用。



关闭并将连接归还到连接池

# 关闭并将连接归还到连接池cur.close()conn.close()

使用连接池过程中需要注意的是,应该在使用完连接后将其归还到连接池中,以确保可以最大程度地重复使用数据库连接。

如以上的例子,如果在每次从连接池中获取一个连接进行操作,使用完后,不关闭,那么连接池数据达到设置的最大值3后,就无法再使用连接池的连接,并且在使用的时候,会报抛出异常raise TooManyConnections


关闭数据库连接池

# 关闭连接池pool.close()

如果在调用close()方法时,连接池中仍有活动的连接,则不会立即关闭连接池。相反,它将等待所有连接都被释放后再关闭连接池。

因此,如果调用close()方法后仍然能够从连接池中获得连接,则说明仍然存在活动的连接。在这种情况下,可以等待一段时间,直到所有连接都被释放,并重新尝试调用close()方法。还可以手动释放所有连接,以便更快地关闭连接池。



PooledDB独立封装

其实和前面分享的

python对Mysql的增、删、改、查操作

九月de云,公众号:九月de云python对Mysql的增、删、改、查操作,独立封装版

类似,只需要将__init__和connect()部分修改即可,

class PooledDB_tools:    def __init__(self):        self.pool = PooledDB(            creator=pymysql,             maxconnections=None,             mincached=2,              maxcached=3,              maxshared=3,            maxusage=0,            reset=True,            blocking=True,            failures=None,            ping=1,            host='localhost',            user='root',            password='111111',            database='test',            charset='utf8mb4',              cursorclass=pymysql.cursors.DictCursor          )
@property def connect(self): """ 启动 :return: """ conn = self.pool.connection() cursor = conn.cursor() return conn, cursor

源码在文章最后,有兴趣的朋友可自取



性能比对


本次以单机写入Mysql为例,分为批量数据写入单数据写入两类,都采用了本篇的PooledDB(组合pymysql)和前期的pandas(组合sqlalchemy)、pymysql这三种方式写入Mysql。

以下的调用方法中会用到前期分享的类方法:

读取csv_tools.read_csv()

csv操作独立封装

九月de云,公众号:九月de云python将Mysql查询的数据保存到csv文件中,csv操作独立封装

pandas写入,mysql.to_sql()

pandas读写mysql独立版

九月de云,公众号:九月de云python对Mysql数据库的增加和查询操作,pandas独立版

pymysql写入

python对Mysql的增、删、改、查操作,独立封装版

九月de云,公众号:九月de云python对Mysql的增、删、改、查操作,独立封装版

这里不再详述,有需要的去直接下载引用即可!


1
批量写入比对
首先准备200万的数据,分别在四个csv文件中:

    user_data1.csv

    user_data2.csv

    user_data3.csv

    user_data4.csv

PooledDB方式写入

# -*- coding: utf-8 -*-import timefrom src.csv.csv_tools import csv_toolsfrom src.mysql_PooledDb.pool_tools import PooledDB_tools
files = ['user_data1.csv', 'user_data2.csv', 'user_data3.csv', 'user_data4.csv']m = PooledDB_tools()sql = f'insert into users_msg(name, age, score) values(%s,%s,%s)'result_ = 0elapsed_ = 0for file in files: ct = csv_tools(file) data_ = ct.read_csv()[0] data = list(map(lambda d: (d['name'], d['age'], d['score']), data_)) start_time = time.time() result = m.insert_many(sql, data) end_time = time.time() result_ += result elapsed = end_time - start_time elapsed_ += elapsedprint("插入", result_, "条数据!")print("耗时:{:.2f}".format(elapsed_), "秒")

结果:

2000000 条数据!
21.67



pandas方式写入

# -*- coding: utf-8 -*-import pandas as pdimport timefrom src.csv.csv_tools import csv_toolsfrom src.mysql_pandas.tools import mysql_pandas
files = ['user_data1.csv', 'user_data2.csv', 'user_data3.csv', 'user_data4.csv']t_name = "users_msg"
mp = mysql_pandas()result_ = 0elapsed_ = 0for file in files: ct = csv_tools(file) data_ = ct.read_csv()[0] data = pd.DataFrame(data_) df = data.drop('id', axis=1) start_time = time.time() result = mp.to_sql(t_name, df, 'append') end_time = time.time() elapsed = end_time - start_time elapsed_ += elapsed result_ += resultprint("插入", result_, "条数据!")print("耗时:{:.2f}".format(elapsed_), "秒")

结果:

2000000 条数据!
30.97



pymysql写入

# -*- coding: utf-8 -*-import time
from src.csv.csv_tools import csv_toolsfrom src.mysql.tools import MysqlTools
files = ['user_data1.csv', 'user_data2.csv', 'user_data3.csv', 'user_data4.csv']
sql = f'insert into users_msg(name, age, score) values(%s,%s,%s)'result_ = 0elapsed_ = 0for file in files: ct = csv_tools(file) data_ = ct.read_csv()[0] data = list(map(lambda d: (d['name'], d['age'], d['score']), data_)) start_time = time.time() m = MysqlTools() result = m.insert_many(sql, data) end_time = time.time() elapsed = end_time - start_time elapsed_ += elapsed result_ += resultprint("插入", result_, "条数据!")print("耗时:{:.2f}".format(elapsed_), "秒")

结果:

2000000 条数据!
26.67



2
单数据写入比对
首先准备1万的数据,存放在csv文件中:

    user_data.csv

PooledDB方式写入

# -*- coding: utf-8 -*-import timefrom src.csv.csv_tools import csv_toolsfrom src.mysql_PooledDb.pooledbd_tools import PooledDB_tools
ct = csv_tools('user_data.csv')data_ = ct.read_csv()[0]data = list(map(lambda d: (d['name'], d['age'], d['score']), data_))m = PooledDB_tools()start_time = time.time()sql = f'insert into users_msg(name, age, score) values(%s,%s,%s)'for i in data: m.insert(sql, i)end_time = time.time()elapsed = end_time - start_timeresult = len(data)print("插入", result, "条数据!")print("耗时:{:.2f}".format(elapsed), "秒")

结果:

插入 10000 条数据!
耗时:14.23



pandas方式写入

# -*- coding: utf-8 -*-import timeimport pandas as pdfrom src.csv.csv_tools import csv_toolsfrom src.mysql_pandas.tools import mysql_pandas
mp = mysql_pandas()t_name = "users_msg"ct = csv_tools('user_data.csv')data = ct.read_csv()[0]start_time = time.time()result = 0for i in [[d] for d in data]: df_ = pd.DataFrame(i) df = df_.drop('id', axis=1) result_ = mp.to_sql(t_name, df, 'append') result += result_end_time = time.time()elapsed = end_time - start_timeprint("插入", result, "条数据!")print("耗时:{:.2f}".format(elapsed), "秒")

结果:

插入 10000 条数据!
耗时:240.02



pymysql写入

# -*- coding: utf-8 -*-import timefrom src.csv.csv_tools import csv_toolsfrom src.mysql.tools import MysqlTools
ct = csv_tools('user_data.csv')data_ = ct.read_csv()[0]data = list(map(lambda d: (d['name'], d['age'], d['score']), data_))sql = f'insert into users_msg(name, age, score) values(%s,%s,%s)'start_time = time.time()for i in data: m = MysqlTools() m.insert(sql, i)end_time = time.time()elapsed = end_time - start_timeresult = len(data)print("插入", result, "条数据!")print("耗时:{:.2f}".format(elapsed), "秒")

结果:

10000 条数据!
120.75



综上统计

实践数据,只作参考。综上所述:

使用数据库连接池PooledDB,效率相对较高一些。

其次是直接使用pymsql。

pandas在写入数据库效率较低些,但它本身是主用于数据分析的。

如果在实际使用过程中,Mysql操作尽量使用PooledDB或直接使用pymysql;数据分析操作,再用pandas,合理的配合,会让工作效率更高。


总结


采用Python中的数据库连接池(PooledDB)提供了许多好处,包括:

1. 提高性能:使用连接池可以节省创建和释放连接的开销,并且可以重复使用已经存在的连接。如此可以更快地响应请求,同时减少数据库服务器的负载。

2. 减少资源消耗:由于连接池可以重复使用现有的连接,因此不需要为每个数据库请求创建一个新的连接,并且可以处理更多的并发请求。这意味着应用程序使用的内存和CPU资源更少。

3. 更好的稳定性:由于连接池会自动管理连接的生命周期,并在需要时关闭或重新创建它们,因此可以降低连接泄漏和死锁等风险。

4. 更方便的编程:使用连接池可以使编程变得更加简单明了。您只需从池中获取一个连接,并使用它来执行数据库操作,然后将其释放回池中即可。连接池会处理所有其他的细节,例如创建和释放连接,以及管理连接的生命周期。

综上所述,使用数据库连接池可以带来许多好处。如果大家工作中需要频繁地与数据库进行交互,那么非常值得考虑选择使用数据库连接池

以上仅代表个人在使用过程中的观点和体会,具体问题仍需要具体考虑。

实践代码做了可公开的简单处理,结构如下:



有需求的朋友可自取哟

获取:后台回复“PooledDB”即可


     

文章就分享到这儿,喜欢就点个吧!



推荐阅读  点击标题可跳转



ISEE小栈
没有花里胡哨,简单才是王道。
 最新文章