python自制简易mysql连接池的实现示例
作者:末日沙兔 发布时间:2023-04-14 20:23:55
目录
连接池是什么?
为什么需要连接池?
连接池的原理是什么?
使用python语言自制简易mysql连接池
开始使用
自定义配置文件名 & 配置标签
命名思路
GitHub地址
今天我们来说一点不一样的, 使用python语言手撸mysql连接池.
连接池是什么?
连接池是创建和管理一个连接的缓冲池的技术,这些连接准备好被任何需要它们的线程使用。在并发量足够时连接池一般比直接连接性能更优, 不仅提高了性能的同时还管理了宝贵的资源.
为什么需要连接池?
讨论这个问题时, 我们需要先了解高并发导致服务器卡顿的原因出在哪里.
正常情况下, 每当一位用户使用各类终端连接到服务器的时候, 服务器都需要开辟一片内存为其服务, 每当一个请求从前端传入都需在mysql之间创建一条连接. 然而过多的连接会导致服务器卡顿内存占用过高, 这时候就需要连接池对所有连接状态进行管理, 合理分配&回收资源.
简单说就是使用连接池技术可用减少服务器压力.
连接池的原理是什么?
连接池主要需要两个参数,默认连接数、最大连接数
当服务启动时, 首先创建默认连接数的空闲连接放入池中.
当用户需要连接时, 首先查看池中是否有空闲连接.
如果小于: 创建新连接交付用户使用.
如果等于: 线程阻塞, 等待有空闲连接再交予用户.
如果有: 由连接池分配从池中取出一个空闲连接交付用户使用.
如果没有: 查看当前存活的所有连接总数是否大于最大连接.
当用户用完连接后, 查看当前存活连接数是否大于默认值.
如果小于等于: 将此条连接重新放入空闲池中, 等待下一次使用.
如果大于: 将此条连接释放销毁, 不放入池中.
使用python语言自制简易mysql连接池
这里, 我们需要 ThemisPool.py 连接池本身, db.cnf 配置文件, 其目录路径如下:
# 推荐目录格式, ThemisPool.py & db.cnf 只需要在同级目录下即可
[your python project]
|
|
|-- util
|
|-- db.cnf
|
|-- ThemisPool.py
ThemisPool.py
# 导入依赖
# mysql连接基本库
import pymysql
# 读取配置文件所需要的库
import configparser
import os
# 线程管理所需要的库
import threading
# 创建配置类用户读取配置文件
class Config(object):
def __init__(self, configFileName='db.cnf'):
file = os.path.join(os.path.dirname(__file__), configFileName)
self.config = configparser.ConfigParser()
self.config.read(file)
def getSections(self):
return self.config.sections()
def getOptions(self, section):
return self.config.options(section)
def getContent(self, section):
result = {}
for option in self.getOptions(section):
value = self.config.get(section, option)
result[option] = int(value) if value.isdigit() else value
return result
# 将连接所需要的参数封装在对象中
# 依次为: 数据库密码、需要连接的库名、主机地址[默认 localhost]、端口号[默认 3306]、初始化连接数[默认 3]、最大连接数[默认 6]
class parameter(object):
def __init__(self, password, database, host="localhost",port="3306" user="root", initsize=3, maxsize=6):
self.host = str(host)
self.port = int(port)
self.user = str(user)
self.password = str(password)
self.database = str(database)
self.maxsize = int(maxsize)
self.initsize = int(initsize)
# 连接池
class ThemisPool(parameter):
def __init__(self, fileName='db.cnf', configName='mysql'):
# 加载配置文件, 配置文件名默认为 'db.cnf', 配置标签默认为 'mysql'
self.config = Config(fileName).getContent(configName)
super(ThemisPool, self).__init__(**self.config)
# 创建队列作为 池
self.pool = queue.Queue(maxsize=self.maxsize)
self.idleSize = self.initsize
# 创建线程锁
self._lock = threading.Lock()
# 初始化连接池
for i in range(self.initsize):
# 创建 初始化连接数 数量的连接放入池中
self.pool.put(self.createConn())
# 启动日志
print('\033[1;32m ThemisPool connect database {database}, login is {user} \033[0m'.format(database=self.database,
user=self.user))
# 生产连接
def createConn(self):
# 使用mysql基本类
# pymysql.connect 参数这里不做解释,具体请查阅官网 https://pypi.org/project/PyMySQL/
return pymysql.connect(host=self.host,
port=self.port,
user=self.user,
password=self.password,
database=self.database,
charset='utf8')
# 获取连接
def getConn(self):
self._lock.acquire()
try:
# 如果池中连接够直接获取
if not self.pool.empty():
self.idleSize -= 1
else:
# 否则重新添加新连接
if self.idleSize < self.maxsize:
self.idleSize += 1
self.pool.put(self.createConn())
finally:
self._lock.release()
return self.pool.get()
# 释放连接
def releaseCon(self, conn=None):
try:
self._lock.acquire()
# 如果池中大于初始值就将多余关闭,否则重新放入池中
if self.pool.qsize() < self.initsize:
self.pool.put(conn)
self.idleSize += 1
else:
try:
# 取出多余连接并关闭
surplus = self.pool.get()
surplus.close()
del surplus
self.idleSize -= 1
except pymysql.ProgrammingError as e:
raise e
finally:
self._lock.release()
# 拉取数据(查询)
# 可用语句类型 (select)
def fetchone(self, sql):
themis = None
cursor = None
try:
themis = self.getConn()
cursor = themis.cursor()
cursor.execute(sql)
return cursor.fetchall()
except pymysql.ProgrammingError as e:
raise e
except pymysql.OperationalError as e:
raise e
except pymysql.Error as e:
raise e
finally:
cursor.close()
self.releaseCon(themis)
# 更新
# 可用语句类型 (insert, update, delete)
def update(self, sql):
themis = None
cursor = None
try:
themis = self.getConn()
cursor = themis.cursor()
cursor.execute(sql)
return cursor.lastrowid
except pymysql.ProgrammingError as e:
raise e
except pymysql.OperationalError as e:
raise e
except pymysql.Error as e:
raise e
finally:
themis.commit()
cursor.close()
self.releaseCon(themis)
# 释放连接池本身
def __del__(self):
try:
while True:
conn = self.pool.get_nowait()
if conn:
conn.close()
except queue.Empty:
pass
db.cnf 配置文件
[mysql]
host = localhost
user = root
password = 12345678
database = practice
initsize = 3
maxsize = 6
所有配置属性
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
host | 主机地址 | str | localhost |
port | 端口号 | int | 3306 |
user | mysql登录用户名 | str | root |
password | mysql登录密码 | str | - |
database | 访问库名 | str | - |
initsize | 初始化连接数 | int | 3 |
maxsize | 最大连接数 | int | 6 |
开始使用
from util.ThemisPool import ThemisPool
# 初始化ThemisPool连接池 (Initialize the ThemisPool connection pool)
db = ThemisPool()
# 查询拉取数据,函数会直接返回数据 (Query pull data.It returns data directly)
selectSql = "select * from user;"
data = db.fetchone(selectSql)
# 增、删、改语句, 如果有使用mysql自增长插入的值函数会返回自增长的数据 (insert,upate delete and alter. If there is a value function inserted using mysql self-growth, it will return self-growth data)
insertSql = "insert into user values(null,'user001','123456')"
id = db.update(selectSql)
自定义配置文件名 & 配置标签
配置文件名默认为 db.cnf, 配置标签默认为 [mysql]
例如自定义配置文件名为 myDB.cnf, 配置标签为 [mysqlConfig]
# myDB.cnf
[mysqlConfig]
host = localhost
user = root
password = 12345678
database = practice
initsize = 3
maxsize = 6
# 使用时
...
db = ThemisPool(fileName='myDB.cnf', configName='mysqlConfig')
...
命名思路
Themis(忒弥斯) 取名来自于古希腊神话中秩序女神的名字, 就如同连接池的作用一样, 管理所有用户的连接, 减少不必要的损耗。
GitHub地址
ThemisPool连接池
来源:https://juejin.cn/post/7022684526891499528


猜你喜欢
- 本文实例讲述了python实现的config文件读写功能。分享给大家供大家参考,具体如下:1、设置配置文件[mysql]host = 123
- 这篇文章主要介绍了Python魔法方法 容器部方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋
- 1.导入模块import cv2 as cvimport numpy as np 2.OpenCV绘图大致步骤OpenCV 图形绘制步骤(1
- 学习Go语言的一些感受,不一定准确。假如发生战争,JAVA一般都是充当航母战斗群的角色。一旦出动,就是护卫舰、巡洋舰、航母舰载机、预警机、电
- Python 变量类型变量存储在内存中的值。这就意味着在创建变量时会在内存中开辟一个空间。基于变量的数据类型,解释器会分配指定内存,并决定什
- python学生成绩管理系统创建,供大家参考,具体内容如下要求编写学生类,班级类,并在电脑运行生成表单,输入一个数字,得到对应的结果。输出样
- 大家一定使用过 phpmyadmin 里面的数据库导入,导出功能,非常方便。但是在实际应用中,我发现如下几个问题:1、数据库超过一定尺寸,比
- 一、*args的使用方法*args 用来将参数打包成tuple给函数体调用def fun(*arg): print(arg,ty
- PDO::errorInfoPDO::errorCode — 返回最后一次操作数据库的错误信息(PHP 5 >= 5.1.0, PEC
- 本节讲解了 flask 的请求,如果想在没有请求的情况下获取上下文,可以使用test_request_context()或者request_
- 有时引用其它js时,其js却使用了window.onload事件,这样的话,引入的页面的onload事件就有可能执行不了,怎样才能两个都运行
- 插入排序 插入排序是这样实现的: 首先新建一个空列表,用于保存已排序的有序数列(我们称之为"有序列表")。
- 这篇文章主要介绍了python scrapy重复执行实现代码详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值
- 本文实例讲述了纯js封装的ajax功能函数与用法。分享给大家供大家参考,具体如下:AJAX = Asynchronous JavaScrip
- 在目标检测的模型训练中, 我们通常都会有一个特征提取网络backbone, 例如YOLO使用的darknet SSD使用的VGG-16。为了
- 本机环境: Windows 10服务器环境: Windows Server 2012 R2背景:公司需要我开发一个简单的web应用。开发的时
- 问题现象从阿里云上镜像过来的一台数据库服务器,SQL Agent服务启动不了,提示服务启动后停止。(原数据库服务器是正常的,怀疑跟镜像有关)
- 对于数字索引数组来说,通过 array_push()函数向数组中添加元素。array_push()函数将数组当成一个栈,将传入的变量压入该数
- 本文实例为大家分享了pygame实现弹球游戏的具体代码,供大家参考,具体内容如下pygame弹球游戏写的很简陋pip install pyg
- 下面的路径介绍针对windows在编写的py文件中打开文件的时候经常见到下面其中路径的表达方式:open('aaa.txt'