网络编程
位置:首页>> 网络编程>> Python编程>> python自制简易mysql连接池的实现示例

python自制简易mysql连接池的实现示例

作者:末日沙兔  发布时间:2023-04-14 20:23:55 

标签:python,mysql,连接池
目录
  • 连接池是什么?

  • 为什么需要连接池?

  • 连接池的原理是什么?

  • 使用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主机地址strlocalhost
    port端口号int3306
    usermysql登录用户名strroot
    passwordmysql登录密码str-
    database访问库名str-
    initsize初始化连接数int3
    maxsize最大连接数int6

    开始使用


    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

    0
    投稿

    猜你喜欢

    手机版 网络编程 asp之家 www.aspxhome.com