数据库连接池

​ 如果在开线程请求数据库中如果觉得所用时间太长的话,就可以通过python数据库连接池去改善一下在此方面的不足之处。

python编程中可以使用pymysql进行数据库连接及增删改查操作,但每次连接mysql请求时,都是独立的去请求访问,比较浪费资源,而且访问数量达到一定数量时,对mysql的性能会产生较大的影响。因此实际使用中,通常会使用数据库的连接池技术,来访问数据库达到资源复用。

连接池对性能的提升:

  • 在程序创建连接的时候,可以从一个空闲的连接中获取,不需要重新初始化连接,提升获取连接的速度。
  • 关闭连接的时候,把连接放回连接池,而不是真正的关闭,所以可以减少频繁的打开和关闭连接。

python的数据库连接池包:DBUtils

DBUtils提供两种外部接口:

  • PersistentDB:提供线程专用的数据库连接,并自动管理连接。
  • PooledDB:提供线程间可共享的数据库连接,并自动管理连接。

DBUtils包安装: pip3 install DBUtils

​ 或者下载 DBUtils 安装包,解压后,使用python setup.py install 命令进行安装

未使用连接池的数据库方法:(app下database)

定义数据库连接类

import pymysql
import pymysql.cursors
from DBUtils.PooledDB import PooledDB

d_host = settings.DATABASES['default']['HOST']
d_port = settings.DATABASES['default']['PORT']
d_user = settings.DATABASES['default']['USER']
d_password = settings.DATABASES['default']['PASSWORD']
d_db = settings.DATABASES['default']['NAME']

class DataBase:
    host, port, user, password, database = d_host, int(d_port), d_user, d_password, d_db

    def __init__(self, host='', port='', user='', password='', database=''):
        if not host == '':
            self.host = host
        if not port == '':
            self.port = int(port)
        if not user == '':
            self.user = user
        if not password == '':
            self.password = password
        if not database == '':
            self.database = database

    def query_sql(self, sql,args=None):
        conn = pymysql.connect(host=self.host, port=self.port, user=self.user, passwd=self.password, db=self.database, charset='utf8', cursorclass=pymysql.cursors.DictCursor)
        cur = conn.cursor()  # 获得 cursor(dict形式).
        if args is None:
            cur.execute(sql)
        else:
            cur.execute(sql, args)  # 通过cursor执行SQL语句.
        result = cur.fetchall()  # 获得数据库操作返回结果.
        cur.close()
        conn.close()
        return result  # 返回查询结果.

    def update_sql(self, sql_str,args=None):
        conn = pymysql.connect(host=self.host, port=self.port, user=self.user, passwd=self.password, db=self.database, charset='utf8', cursorclass=pymysql.cursors.DictCursor)
        cur = conn.cursor()
        cur.execute('begin')
        if args is None:
            result = cur.execute(sql_str)
        else:
            result = cur.execute(sql_str,args)
        cur.execute('commit')
        cur.close()
        conn.close()
        return result

    def execute_sql(self, sql,args=None):
        conn = pymysql.connect(host=self.host, port=self.port, user=self.user, passwd=self.password, db=self.database, charset='utf8', cursorclass=pymysql.cursors.DictCursor)
        cur = conn.cursor()
        if args is None:
            cur.execute(sql)
        else:
            cur.execute(sql, args)
        conn.commit()
        result = cur.lastrowid
        cur.close()
        conn.close()
        return result
调用方法

db = database.DB()
sql = """
    select * from course
"""
result = db.query_sql(sql)

用数据库连接池后的方法:

定义数据库连接类

import pymysql
import pymysql.cursors
from DBUtils.PooledDB import PooledDB

d_host = settings.DATABASES['default']['HOST']
d_port = settings.DATABASES['default']['PORT']
d_user = settings.DATABASES['default']['USER']
d_password = settings.DATABASES['default']['PASSWORD']
d_db = settings.DATABASES['default']['NAME']


PY_MYSQL_CONN_DICT = {
    "host": d_host,
    "port": int(d_port),
    "user": d_user,
    "passwd": d_password,
    "db": d_db,
    'charset': 'utf8',
}

class SQLPoll(object):

    # docstring for DbConnection

    __poll = None

    def __init__(self):
        self.pool = self.__get_db()
        self.conn = self.pool.connection()
        self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)

    @classmethod
    def __get_db(cls):
        if cls.__poll is None:
            cls.__poll = PooledDB(
                creator=pymysql,
                mincached=10,
                maxconnections=100,
                **PY_MYSQL_CONN_DICT)
        return cls.__poll

    def fetch_all(self, sql, args=None):
        if args is None:
            self.cursor.execute(sql)
        else:
            self.cursor.execute(sql, args)
        result = self.cursor.fetchall()
        return result

    def fetch_one(self, sql, args=None):
        if args is None:
            self.cursor.execute(sql)
        else:
            self.cursor.execute(sql, args)
        result = self.cursor.fetchone()
        return result

    def execute(self, sql, args):
        self.cursor.execute(sql, args)
        self.conn.commit()
        result = self.cursor.lastrowid
        return result

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

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.__close()

使用方法

sql = """select * from course where id > %s"""
args = (10,)
with SQLPoll() as db:
    course_list = db.fetch_all(sql,args)

  

PooledDB可选参数解释:

  1. mincached,最少的空闲连接数,如果空闲连接数小于这个数,pool会创建一个新的连接。
  2. maxcached,最大的空闲连接数,如果空闲连接数大于这个数,pool会关闭空闲连接。
  3. maxconnections,最大的连接数,进程中最大可创建的线程数。
  4. blocking, 当连接数达到最大连接数时,再次请求时,如果这个值是True,请求连接的程序会一直等待,直到当前连接数小于最大连接数;如果这个值为False,会报错。
  5. masxshared,当连接数达到这个数时,新请求的连接会分享已经分配出去的连接。

在uwsgi中,每个http请求都会有一个进程,连接池中配置的连接数都是一个进程为单位的(即上面的最大连接数,都是在一个进程中创建的线程数),如果业务中,一个http请求中需要的sql连接数不是很多的话(其实大多数都只需要创建一个连接),配置的连接数配置都不需要太大。

posted on 2020-12-31 14:05  我爱罗2012  阅读(75)  评论(0编辑  收藏  举报