Oracle 连接池第四版。
编程语言 | Python |
语言版本 | 3.5.3 |
实现功能 | oracle 连接池,解决频繁连接oracle数据库带来的连接资源耗费问题 |
程序托管 | GitHub-OraclePool |
修改日期 | 2020年8月3日 |
version 4.0 改进说明:
**[2020-04-21]**
+ 修复连接用完后,不放回连接池的`bug`
+ 修复使用类名称获取`pool`时的类名称错误(`OrclConnPool`),改为用`self`
+ 改进了对`config`连接信息的判断逻辑,使得`config`的配置更加简化
+ 改进了新的注释,使用更加清晰
+ 改进了部分代码的格式,使得其更规范
+ 新增`fetch_all`和`fetch_one`
+ 优化了`demo`内容和格式,使得其更规范
程序源码:
# -*- coding: utf-8 -*-
"""
--------------------------------------
@File : oracle_pool.py
@Author : maixiaochai
@Created on : 2020/4/21 15:47
--------------------------------------
"""
import cx_Oracle as Oracle
from DBUtils.PooledDB import PooledDB
class OraclePool:
"""
1) 这里封装了一些有关oracle连接池的功能;
2) sid和service_name,程序会自动判断哪个有值,
若两个都有值,则默认使用service_name;
3) 关于config的设置,注意只有 port 的值的类型是 int,以下是config样例:
config = {
'user': 'maixiaochai',
'password': 'maixiaochai',
'host': '192.168.158.1',
'port': 1521,
'sid': 'maixiaochai',
'service_name': 'maixiaochai'
}
"""
def __init__(self, config):
"""
获得连接池
:param config: dict Oracle连接信息
"""
self.__pool = self.__get_pool(config)
@staticmethod
def __get_pool(config):
"""
:param config: dict 连接Oracle的信息
---------------------------------------------
以下设置,根据需要进行配置
maxconnections=6, # 最大连接数,0或None表示不限制连接数
mincached=2, # 初始化时,连接池中至少创建的空闲连接。0表示不创建
maxcached=5, # 连接池中最多允许的空闲连接数,很久没有用户访问,连接池释放了一个,由6个变为5个,
# 又过了很久,不再释放,因为该项设置的数量为5
maxshared=0, # 在多个线程中,最多共享的连接数,Python中无用,会最终设置为0
blocking=True, # 没有闲置连接的时候是否等待, True,等待,阻塞住;False,不等待,抛出异常。
maxusage=None, # 一个连接最多被使用的次数,None表示无限制
setession=[], # 会话之前所执行的命令, 如["set charset ...", "set datestyle ..."]
ping=0, # 0 永远不ping
# 1,默认值,用到连接时先ping一下服务器
# 2, 当cursor被创建时ping
# 4, 当SQL语句被执行时ping
# 7, 总是先ping
"""
dsn = None
host, port = config.get('host'), config.get('port')
if 'service_name' in config:
dsn = Oracle.makedsn(host, port, service_name=config.get('service_name'))
elif 'sid' in config:
dsn = Oracle.makedsn(host, port, sid=config.get('sid'))
pool = PooledDB(
Oracle,
mincached=5,
maxcached=10,
user=config.get('user'),
password=config.get('password'),
dsn=dsn
)
return pool
def __get_conn(self):
"""
从连接池中获取一个连接,并获取游标。
:return: conn, cursor
"""
conn = self.__pool.connection()
cursor = conn.cursor()
return conn, cursor
@staticmethod
def __reset_conn(conn, cursor):
"""
把连接放回连接池。
:return:
"""
cursor.close()
conn.close()
def __execute(self, sql, args=None):
"""
执行sql语句
:param sql: str sql语句
:param args: list sql语句参数列表
:param return: cursor
"""
conn, cursor = self.__get_conn()
if args:
cursor.execute(sql, args)
else:
cursor.execute(sql)
return conn, cursor
def fetch_all(self, sql, args=None):
"""
获取全部结果
:param sql: str sql语句
:param args: list sql语句参数
:return: tuple fetch结果
"""
conn, cursor = self.__execute(sql, args)
result = cursor.fetchall()
self.__reset_conn(conn, cursor)
return result
def fetch_one(self, sql, args=None):
"""
获取全部结果
:param sql: str sql语句
:param args: list sql语句参数
:return: tuple fetch结果
"""
conn, cursor = self.__execute(sql, args)
result = cursor.fetchone()
self.__reset_conn(conn, cursor)
return result
def execute_sql(self, sql, args=None):
"""
执行SQL语句。
:param sql: str sql语句
:param args: list sql语句参数
:return: tuple fetch结果
"""
conn, cursor = self.__execute(sql, args)
conn.commit()
self.__reset_conn(conn, cursor)
def __del__(self):
"""
关闭连接池。
"""
self.__pool.close()
def demo():
config = {
'user': 'maixiaochai',
'password': 'maixiaochai',
'host': '192.168.158.1',
'port': 1521,
'sid': 'maixiaochai',
'service_name': 'maixiaochai'
}
sql = "SELECT COUNT(*) FROM MAIXIAOCHAI"
orcl = OraclePool(config)
result = orcl.fetch_all(sql)
print(result)
if __name__ == "__main__":
demo()
version 3.0 改进说明:
*)修复一个 Bug,该 Bug导致连接池中有且仅有一个连接资源被使用,其余空闲。
*) 2019-12-27 12:45:21 by MaiXiaochai
*)将原来的 orcl_pool.py 文件单独拿出来,创建新库 OracleConnectionPool,便于编辑和分享;
*)更新"程序链接"内容和 URL。
*)2019-5-29 16:54:37 by MaiXiaochai
*)由原来的只能维持一个连接池改为可维持多个连接池;
*)加入了对 service_name 连接方式的支持;
*)添加了析构函数,对连接池资源进行回收;
*)对相关的代码注释进行了规范,使其看起来比较整洁;
*)添加了一个使用样例。
*)2019-3-28 19:13:47 by MaiXiaochai
程序源码:
version 3.0
# -*- coding: utf-8 -*-
# @File: oracle_conn_pool.py
# @Project: OraclePool
# @Date: 2019/5/29 15:19
# @Author: MaiXiaochai
# @Modify: 2020/1/6 16:02
import cx_Oracle as Oracle
from DBUtils.PooledDB import PooledDB
class OraclePool(object):
"""
1) 这里封装了一些有关oracle连接池的功能;
2) sid和service_name,程序会自动判断哪个有值,
若两个都有值,则默认使用sid;
若只想用其中一个,则只需要把另一个设置为空即可。如,service_name = ''
3) 关于config的设置,注意只有 port 的值的类型是 int,以下是config样例:
orcl_cfg = {
'user': 'user_name_str',
'passwd': 'passwd_str',
'host': 'xxx.xxx.xxx.xxx_str',
'port': port_int,
'sid': 'sid_str',
'service_name': 'service_name_str'}
"""
def __init__(self, config):
self.pool = OrclConnPool.__get_pool(config)
@staticmethod
def __get_pool(conf):
"""
一些 PoolDB 中可能会用到的参数,根据实际情况自己选择
mincached: 启动时开启的空连接数量
maxcached: 连接池最大可用连接数量
maxshared: 连接池最大可共享连接数量
maxconnections: 最大允许连接数量
blocking: 达到最大数量时是否阻塞
maxusage: 单个连接最大复用次数
:param conf: dict 连接Oracle的信息
"""
host, port, sid, service_name = conf.get('host'), conf.get('port'), conf.get('sid'), conf.get('service_name')
dsn = None
if sid:
dsn = Oracle.makedsn(host, port, sid=sid)
elif service_name:
dsn = Oracle.makedsn(host, port, service_name=conf.get('service_name'))
__pool = PooledDB(Oracle, user=conf['user'], password=conf['passwd'], dsn=dsn, mincached=5, maxcached=30)
return __pool
def execute_sql(self, sql, args=None):
"""
执行sql语句
:param sql: str sql语句
:param args: list sql语句参数列表
"""
cur = self.pool.connection().cursor()
if args:
cur.execute(sql, args)
else:
cur.execute(sql)
def fetch_all(self, sql, args=None):
"""
获取全部结果
:param sql: str sql语句
:param args: list sql语句参数
:return: tuple fetch结果
"""
cur = self.pool.connection().cursor()
if args:
cur.execute(sql, args)
else:
cur.execute(sql)
return cur.fetchall()
def __del__(self):
"""
在实例资源被回收时,关闭该连接池
"""
try:
self.pool.close()
except Exception:
pass
def simple_demo():
orcl_cfg = {
'user': 'hello',
'passwd': 'Python',
'host': '192.168.158.xxx',
'port': 1521,
'sid': '',
'service_name': 'MaiXiaochai'}
test_sql = "SELECT COUNT(1) FROM TEST_PYTHON"
orcl = OraclePool(orcl_cfg)
orcl.execute_sql(test_sql)
res = orcl.cur.fetchone()
print(res)
if __name__ == "__main__":
simple_demo()
传送门:GitHub:OraclePool
The end.