Python+sqlite:一個簡單的數據庫連接池


  1 import sqlite3
  2 import os
  3 from threading import Lock, BoundedSemaphore
  4 
  5 
  6 class ConnPool:
  7 
  8     def __init__(self, db_name, max_conn):
  9         self.__MaxConn = max_conn  # 最大連接數
 10         self.__CurConn = 0  # 當前連接數
 11         self.__FreeConn = 0  # 空閑連接數
 12         self.__lock = Lock()  #
 13         self.__connList = []  # 連接池
 14 
 15         self.dbName = db_name  # 數據庫名稱
 16         self.init_conn()  # 初始化
 17 
 18     def init_conn(self):
 19         for i in range(self.__MaxConn):
 20             try:
 21                 conn = sqlite3.connect(os.path.abspath('.') + '\\' + self.dbName + '.db', check_same_thread=False)
 22                 if conn is not None:
 23                     self.__connList.append(conn)  # 將獲取到的數據庫連接加入連接池
 24                     self.__FreeConn += 1
 25             except Exception as e:
 26                 print("Get Sqlite Connection Failed: {0}".format(i) + e)
 27         self.__sem = BoundedSemaphore(self.__FreeConn)  # 初始化信號量
 28         self.__MaxConn = self.__FreeConn
 29 
 30     # 每當有請求時,從數據庫連接池中返回一個可用連接,並更新使用和空閑連接數
 31     def get_connection(self):
 32         if 0 == len(self.__connList):
 33             return None
 34         self.__sem.acquire()  # 消耗資源使計數器遞減,為0時阻塞調用
 35         self.__lock.acquire()  # 加鎖
 36         conn = self.__connList.pop()  # 從連接列表中彈出一個數據庫連接
 37 
 38         self.__FreeConn -= 1  # 空閑連接計數-1
 39         self.__CurConn += 1  # 當前連接計數+1
 40 
 41         self.__lock.release()  # 釋放鎖
 42         return conn
 43 
 44     # 釋放當前使用的連接
 45     def release_connection(self, conn):
 46         if conn is None:
 47             return False
 48 
 49         self.__lock.acquire()       # 加鎖
 50 
 51         self.__connList.append(conn)    # 歸還數據庫連接
 52         self.__FreeConn += 1
 53         self.__CurConn -= 1
 54 
 55         self.__lock.release()   # 釋放鎖
 56         try:
 57             self.__sem.release()    # 歸還資源使計數器遞增
 58         except ValueError:
 59             print("超出計數器上限.")
 60         return True
 61 
 62     # 銷毀數據庫連接池
 63     def destroy_pool(self):
 64         self.__lock.acquire()       # 加鎖
 65         if len(self.__connList) > 0:
 66             for it in self.__connList:
 67                 it.close()
 68             self.__CurConn = 0
 69             self.__FreeConn = 0
 70             self.__connList.clear()
 71         self.__lock.release()       # 釋放鎖
 72 
 73     # 獲取空閑的連接數
 74     def get_free_conn(self):
 75         return self.__FreeConn
 76 
 77     # 析構函數
 78     def __del__(self):
 79         self.destroy_pool()
 80 
 81 
 82 # 創建一個數據庫資源管理類,傳入一個類型為ConnPool對象,生成一個數據庫連接,析構函數中釋放此連接
 83 class ConnPoolRAII:
 84     def __init__(self, conn_pool: ConnPool):
 85         self.connRAII = conn_pool.get_connection()
 86         self.poolRAII = conn_pool
 87         self.__lock = Lock()    # 數據庫操作鎖
 88         self.init_db()          # 初始化數據庫
 89 
 90     # 數據庫初始化
 91     def init_db(self):
 92         # 若用於存儲下位機的表不存在,則進行初始化創建
 93         if not self.is_exist('Client'):
 94             self.operate('''create table Client(
 95                             ID integer primary key autoincrement,
 96                             Client_name text(10) not null,
 97                             IPAddress text(20) not null,
 98                             Status numeric default 0
 99                             )''')
100 
101     # 檢查指定表是否存在
102     def is_exist(self, table_name):
103         res = self.query('''select count(*) from sqlite_master where type='table' and name='{0}'
104                         '''.format(table_name))
105         if res.fetchone()[0] == 0:
106             return False
107         return True
108 
109     # 為每一個客戶機創建一個用於存儲數據的表格
110     def create_table(self, client_name):
111         return self.operate('''
112                     create table {0}(
113                         ID integer primary key autoincrement,
114                         Weight real default 0,
115                         Temperature real default 0,
116                         Date integer not null
117                         );
118                         '''.format(client_name))
119 
120     # 新增客戶機函數
121     def add_client(self, ip):
122         client_name = 'Client{0}'.format(ip[ip.rfind('.') + 1:])    # 獲取客戶端名稱,以Clientxxx為格式
123         res = self.query("select * from Client where IPAddress=='{0}'".format(client_name))     # 查詢Client表中是否存在當前客戶端信息
124         sql_insert = "insert into Client (Client_name, IPAddress) values ('{0}','{1}')".format(client_name, ip)
125         if res and (res.fetchone() is None):
126             if self.operate(sql_insert) and self.create_table(client_name):
127                 print("創建表成功")      # 測試用,后續改為日志
128                 return True
129             else:
130                 print("創建表失敗,檢查客戶端是否已存在!")
131                 return False
132 
133     # 用於查詢類操作,要求輸入sql語句
134     def query(self, sql):
135         self.__lock.acquire()       # 加鎖
136         c = self.connRAII.cursor()  # 獲取cursor
137         try:
138             res = c.execute(sql)    # 執行sql
139             self.__lock.release()   # 釋放鎖
140             return res              # 返回查詢結果
141         except Exception as e:
142             print(e)
143             self.__lock.release()   # 釋放鎖
144             return False            # 返回False
145 
146     # 增刪改等操作,提供sql語句,返回bool值
147     def operate(self, sql):
148         self.__lock.acquire()       # 加鎖
149         c = self.connRAII.cursor()  # 獲取cursor
150         try:
151             c.execute(sql)          # 執行sql
152             self.connRAII.commit()  # 提交執行結果
153             self.__lock.release()   # 釋放鎖
154             return True             # 返回操作成功
155         except Exception as e:
156             print(e)                # 打印錯誤信息
157             self.__lock.release()   # 釋放鎖
158             return False            # 返回False
159 
160     # 析構函數
161     def __del__(self):
162         self.poolRAII.release_connection(self.connRAII)

 


免責聲明!

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



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