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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM