Python 实现简单的sqlhelper

本文介绍了如何使用Python的DBUtils模块创建一个PooledDB数据库连接池,以方便高效地访问MySQL数据库。通过设置最大连接数、初始化连接数等参数,确保在多线程环境下连接的管理和复用。同时,展示了使用with语句结合threading.local()进行连接管理,以避免线程之间的干扰。
摘要由CSDN通过智能技术生成

经常使用Python连接mysql数据库,我们需要设计一个sqlHelper来方便我们访问mysql数据库,我们使用DBUtils.PooledDB来创建一个数据库连接池,每次请求从连接池中获取一个数据库连接。

首先安装pymysqlDBUtils

pip install pymysql==1.0.2
pip install DBUtils==3.0.2

构建SqlHelper

import pymysql
from dbutils.pooled_db import PooledDB

class SqlHelper(object):
    def __init__(self):
        self.pool = PooledDB(
            creator=pymysql,  # 使用链接数据库的模块
            maxconnections=6,  # 连接池允许的最大连接数,0和None表示不限制连接数
            mincached=2,  # 初始化时,链接池中至少创建的链接,0表示不创建
            blocking=True,  # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
            ping=0,
            # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
            host='192.168.171.45',
            port=3306,
            user='root',
            password='123456',
            database='vincent',
            charset='utf8'
        )

    def open(self):
        conn = self.pool.connection()
        cursor = conn.cursor()
        return conn,cursor

    def close(self,cursor,conn):
        cursor.close()
        conn.close()

    def fetchall(self,sql, *args):
        """ 获取所有数据 """
        conn,cursor = self.open()
        cursor.execute(sql, args)
        result = cursor.fetchall()
        self.close(conn,cursor)
        return result

    def fetchone(self,sql, *args):
        """ 获取所有数据 """
        conn, cursor = self.open()
        cursor.execute(sql, args)
        result = cursor.fetchone()
        self.close(conn, cursor)
        return result

	def __enter__(self):
        return self.open()[1]

    def __exit__(self):
        pass

db = SqlHelper()
print(db)

测试数据库连接池:

from SqlHelper import db

def task(num):
    # 去连接池中获取一个连接
    conn,cursor = db.open()
    cursor.execute('select sleep(3)') # 在数据库执行3秒钟
    result = cursor.fetchall()
    cursor.close()
    # 将连接放会到连接池
    conn.close()
    print(num,'------------>',result)


from threading import Thread
for i in range(57):
    t = Thread(target=task,args=(i,))
    t.start()

我们执行了数据库停顿3秒的sql请求,判断连接池的最大连接数。运行程序输出时,每隔6个会输出一次,可以说明连接池的最大连接数是6个。

with 上下文

我们可以结合with上下文,来进行优化一下:

def task(num):
    with db as cursor:
        cursor.excute('select sleep(3)')
        result = cursor.fetchall()


from threading import Thread
for i in range(57):
    t = Thread(target=task,args=(i,))
    t.start()

但是需要注意的是,虽然使用了with,自动执行了__enter__赋值给了cursor,但是在多线程中,如何自动执行close(),可以使得线程释放连接。因为在多线程下,不加干涉的话,每个线程都会干涉彼此(因为我们上面是单例模式,只有一个对象,彼此会干涉),因此需要一个地方可以标识出当前的线程。

因此需要引入threading.local()

threading.local()

class SqlHelper(object):
    def __init__(self):
        self.pool = PooledDB(
            creator=pymysql,  # 使用链接数据库的模块
            maxconnections=6,  # 连接池允许的最大连接数,0和None表示不限制连接数
            mincached=2,  # 初始化时,链接池中至少创建的链接,0表示不创建
            blocking=True,  # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
            ping=0,
            # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
            host='192.168.171.45',
            port=3306,
            user='root',
            password='123456',
            database='vincent',
            charset='utf8'
        )
        self.local = threading.local()

    def open(self):
        conn = self.pool.connection()
        cursor = conn.cursor()
        return conn,cursor

    def close(self,cursor,conn):
        cursor.close()
        conn.close()

    def fetchall(self,sql, *args):
        """ 获取所有数据 """
        conn,cursor = self.open()
        cursor.execute(sql, args)
        result = cursor.fetchall()
        self.close(conn,cursor)
        return result

    def fetchone(self,sql, *args):
        """ 获取所有数据 """
        conn, cursor = self.open()
        cursor.execute(sql, args)
        result = cursor.fetchone()
        self.close(conn, cursor)
        return result
    
    def __enter__(self):
        conn, cursor = self.open()
        rv = getattr(self.local, 'stack', None)
        if not rv:
            self.local.stack = [(conn, cursor)]
        else:
            rv.append((conn, cursor))
            self.local.stack = rv
        return cursor

    def __exit__(self): # 根据不同的线程关闭对应的conn和cursor
        rv = getattr(self.local, 'stack', None)
        if not rv:
            # del self.local.stack
            return
        conn, cursor = self.local.stack.pop()
        cursor.close()
        conn.close()


db = SqlHelper()

测试:

def task(num):
    with db as cursor:
        cursor.excute('select sleep(3)')
        result = cursor.fetchall()


from threading import Thread
for i in range(57):
    t = Thread(target=task,args=(i,))
    t.start()
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值