python 数据库连接池

对于一个简单的数据库应用,由于对于数据库的访问不是很频繁。这时可以简单地在需要访问数据库时,就新创建一个连接,用完后就关闭它,这样做也不会带来什么明显的性能上的开销。但是对于一个复杂的数据库应用,情况就完全不同了。频繁的建立、关闭连接,会极大的减低系统的性能,因为对于连接的使用成了系统性能的瓶颈。

连接复用。通过建立一个数据库连接池以及一套连接使用管理策略,使得一个数据库连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销。

对于共享资源,有一个很著名的设计模式:资源池。该模式正是为了解决资源频繁分配、释放所造成的问题的。把该模式应用到数据库连接管理领域,就是建立一个数据库连接池,提供一套高效的连接分配、使用策略,最终目标是实现连接的高效、安全的复用。


数据库连接池的基本原理是在内部对象池中维护一定数量的数据库连接,并对外暴露数据库连接获取和返回方法。如:

外部使用者可通过getConnection 方法获取连接,使用完毕后再通过releaseConnection 方法将连接返回,注意此时连接并没有关闭,而是由连接池管理器回收,并为下一次使用做好准备。

数据库连接池技术带来的优势

1. 资源重用

由于数据库连接得到重用,避免了频繁创建、释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数量)。

2. 更快的系统响应速度

数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。

3. 新的资源分配手段

对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接的配置,实现数据库连接池技术,几年钱也许还是个新鲜话题,对于目前的业务系统而言,如果设计中还没有考虑到连接池的应用,那么…….快在设计文档中加上这部分的内容吧。某一应用最大可用数据库连接数的限制,避免某一应用独占所有数据库资源。

4. 统一的连接管理,避免数据库连接泄漏

在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用连接。从而避免了常规数据库连接操作中可能出现的资源泄漏。一个最小化的数据库连接池实现:

  1 import pymysql
  2 import os
  3 import configparser
  4 from pymysql.cursors import DictCursor
  5 from dbutils.pooled_db import PooledDB
  6 
  7 
  8 class Config(object):
  9     """
 10     # Config().get_content("user_information")
 11     配置文件里面的参数
 12     [dbMysql]
 13     host = 192.168.1.180
 14     port = 3306
 15     user = root
 16     password = 123456
 17     """
 18 
 19     def __init__(self, config_filename="config.ini"):
 20         file_path = os.path.join(os.path.dirname(__file__), config_filename)
 21         self.cf = configparser.ConfigParser()
 22         self.cf.read(file_path)
 23 
 24     def get_sections(self):
 25         return self.cf.sections()
 26 
 27     def get_options(self, section):
 28         return self.cf.options(section)
 29 
 30     def get_content(self, section):
 31         result = {}
 32         for option in self.get_options(section):
 33             value = self.cf.get(section, option)
 34             result[option] = int(value) if value.isdigit() else value
 35         return result
 36 
 37 
 38 class BasePymysqlPool(object):
 39     def __init__(self, host, port, user, password, db_name):
 40         self.db_host = host
 41         self.db_port = int(port)
 42         self.user = user
 43         self.password = str(password)
 44         self.db = db_name
 45         self.conn = None
 46         self.cursor = None
 47 
 48 
 49 class MyPymysqlPool(BasePymysqlPool):
 50     """
 51     MYSQL数据库对象,负责产生数据库连接 , 此类中的连接采用连接池实现
 52         获取连接对象:conn = Mysql.getConn()
 53         释放连接对象;conn.close()或del conn
 54     """
 55     # 连接池对象
 56     __pool = None
 57 
 58     def __init__(self, conf_name=None):
 59         self.conf = Config().get_content(conf_name)
 60         super(MyPymysqlPool, self).__init__(**self.conf)
 61         # 数据库构造函数,从连接池中取出连接,并生成操作游标
 62         self._conn = self.__getConn()
 63         self._cursor = self._conn.cursor()
 64 
 65     def __getConn(self):
 66         """
 67         @summary: 静态方法,从连接池中取出连接
 68         @return MySQLdb.connection
 69         """
 70         if MyPymysqlPool.__pool is None:
 71             __pool = PooledDB(creator=pymysql,
 72                               mincached=1,
 73                               maxcached=20,
 74                               host=self.db_host,
 75                               port=self.db_port,
 76                               user=self.user,
 77                               passwd=self.password,
 78                               db=self.db,
 79                               use_unicode=True,
 80                               charset="utf8",
 81                               cursorclass=DictCursor)
 82             # print("12211212")
 83         return __pool.connection()
 84 
 85     def getAll(self, sql, param=None):
 86         """
 87         @summary: 执行查询,并取出所有结果集
 88         @param sql:查询SQL,如果有查询条件,请只指定条件列表,并将条件值使用参数[param]传递进来
 89         @param param: 可选参数,条件列表值(元组/列表)
 90         @return: result list(字典对象)/boolean 查询到的结果集
 91         """
 92         if param is None:
 93             count = self._cursor.execute(sql)
 94         else:
 95             count = self._cursor.execute(sql, param)
 96         if count > 0:
 97             result = self._cursor.fetchall()
 98         else:
 99             result = False
100         return result
101 
102     def getOne(self, sql, param=None):
103         """
104         @summary: 执行查询,并取出第一条
105         @param sql:查询SQL,如果有查询条件,请只指定条件列表,并将条件值使用参数[param]传递进来
106         @param param: 可选参数,条件列表值(元组/列表)
107         @return: result list/boolean 查询到的结果集
108         """
109         if param is None:
110             count = self._cursor.execute(sql)
111         else:
112             count = self._cursor.execute(sql, param)
113         if count > 0:
114             result = self._cursor.fetchone()
115         else:
116             result = False
117         return result
118 
119     def getMany(self, sql, num, param=None):
120         """
121         @summary: 执行查询,并取出num条结果
122         @param sql:查询SQL,如果有查询条件,请只指定条件列表,并将条件值使用参数[param]传递进来
123         @param num:取得的结果条数
124         @param param: 可选参数,条件列表值(元组/列表)
125         @return: result list/boolean 查询到的结果集
126         """
127         if param is None:
128             count = self._cursor.execute(sql)
129         else:
130             count = self._cursor.execute(sql, param)
131         if count > 0:
132             result = self._cursor.fetchmany(num)
133         else:
134             result = False
135         return result
136 
137     def insertMany(self, sql, values):
138         """
139         @summary: 向数据表插入多条记录
140         @param sql:要插入的SQL格式
141         @param values:要插入的记录数据tuple(tuple)/list[list]
142         @return: count 受影响的行数
143         """
144         count = self._cursor.executemany(sql, values)
145         return count
146 
147     def __query(self, sql, param=None):
148         if param is None:
149             count = self._cursor.execute(sql)
150         else:
151             count = self._cursor.execute(sql, param)
152         return count
153 
154     def update(self, sql, param=None):
155         """
156         @summary: 更新数据表记录
157         @param sql: SQL格式及条件,使用(%s,%s)
158         @param param: 要更新的  值 tuple/list
159         @return: count 受影响的行数
160         """
161         return self.__query(sql, param)
162 
163     def insert(self, sql, param=None):
164         """
165         @summary: 更新数据表记录
166         @param sql: SQL格式及条件,使用(%s,%s)
167         @param param: 要更新的  值 tuple/list
168         @return: count 受影响的行数
169         """
170         return self.__query(sql, param)
171 
172     def delete(self, sql, param=None):
173         """
174         @summary: 删除数据表记录
175         @param sql: SQL格式及条件,使用(%s,%s)
176         @param param: 要删除的条件 值 tuple/list
177         @return: count 受影响的行数
178         """
179         return self.__query(sql, param)
180 
181     def begin(self):
182         """
183         @summary: 开启事务
184         """
185         self._conn.autocommit(0)
186 
187     def end(self, option='commit'):
188         """
189         @summary: 结束事务
190         """
191         if option == 'commit':
192             self._conn.commit()
193         else:
194             self._conn.rollback()
195 
196     def dispose(self, isEnd=1):
197         """
198         @summary: 释放连接池资源
199         """
200         if False not in isEnd:
201             self.end('commit')
202         else:
203             print("sql错误,rollback")
204             self.end('rollback')
205         self._cursor.close()
206         self._conn.close()
207 
208 
209 # 调用方法
210 if __name__ == '__main__':
211     mysql = MyPymysqlPool("dbMysql")
212     sqlAll = "show tables;"
213     result = mysql.getAll(sqlAll)
214     print(result)
215     # 释放资源
216     mysql.dispose(isEnd=[result, result])

配置mysql参数

1 [dbMysql]
2 host = 192.168.1.2
3 port = 3306
4 user = root
5 password = root
6 db_name = test
原文地址:https://www.cnblogs.com/liang715200/p/14787938.html