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