简介
在使用数据库时,连接池是一种常用的技术,它可以提高数据库连接的复用性和性能,同时有效地管理数据库连接的创建和关闭。本文介绍了如何使用Python编写一个简单而高效的Oracle数据库连接池,通过优化和封装,使连接获取和释放变得简单和可靠。
依赖环境:
python:3.5 (windows下相同,jdk的位数和Python位数保持一致即可)
jaydebeapi:用于在Python中使用JDBC连接数据库,版本1.2.3
jpype:用于在Python中启动Java虚拟机(JVM),版本 JPype1==0.7.1
odbc.jar: 版本 8.0
操作系统: Linux 、Windows
jdk: jdk1.8.0_181 64
依赖获取:
代码展示
Oracle连接池类
import jaydebeapi
import jpype
from threading import Semaphore
import logging
class OracleConnectionPool:
def __init__(self, jdbc_driver_path, jdbc_class_name, url, username, password, max_connections=20):
self.jdbc_driver_path = jdbc_driver_path
self.jdbc_class_name = jdbc_class_name
self.url = url
self.username = username
self.password = password
self.max_connections = max_connections
# 通过信号量的形式控制连接的数量,也支持Queue方式实现
self.semaphore = Semaphore(max_connections)
self.connections = []
self._initialize_pool()
def _initialize_pool(self):
jpype.startJVM(jpype.getDefaultJVMPath(), "-Djava.class.path={}".format(self.jdbc_driver_path), convertStrings=False)
conn_properties = {
"user": self.username,
"password": self.password
}
for _ in range(self.max_connections):
try:
conn = jaydebeapi.connect(self.jdbc_class_name, self.url, conn_properties)
self.connections.append(conn)
except Exception as e:
logging.error(f"Failed to initialize connection: {str(e)}")
# 验证连接的合法性
def _is_connection_valid(self, conn):
try:
cursor = conn.cursor()
cursor.execute("SELECT 1 FROM DUAL")
cursor.close()
return True
except Exception:
return False
# 重新建立连接
def _recreate_connection(self):
conn_properties = {
"user": self.username,
"password": self.password
}
return jaydebeapi.connect(self.jdbc_class_name, self.url, conn_properties)
# 获取连接,可配置超时时间
def get_connection(self, timeout=None):
if not self.semaphore.acquire(timeout=timeout):
raise Exception("Timeout: Failed to acquire connection from the pool.")
try:
for conn in self.connections:
if self._is_connection_valid(conn):
return conn
else:
new_conn = self._recreate_connection()
self.connections.append(new_conn)
return new_conn
except Exception as e:
self.semaphore.release()
raise Exception(f"Failed to get connection: {str(e)}")
# 将连接放回连接池
def close_connection(self, conn):
try:
self.connections.append(conn)
except Exception as e:
logging.error(f"Failed to close connection: {str(e)}")
finally:
self.semaphore.release()
# 关闭连接池
def close_pool(self):
for conn in self.connections:
try:
conn.close()
except Exception as e:
logging.error(f"Failed to close connection: {str(e)}")
self.connections = []
jpype.shutdownJVM()
# 可以修改连接池最大容量
def set_max_connections(self, max_connections):
self.semaphore = Semaphore(max_connections)
查询执行器类
class OracleQueryExecutor:
def __init__(self, pool):
self.pool = pool
def execute_query(self, sql):
conn = self.pool.get_connection(10)
try:
cursor = conn.cursor()
cursor.execute(sql)
result = cursor.fetchall()
cursor.close()
return result
finally:
self.pool.close_connection(conn)
连接池示例用法
jdbc_driver_path = 'ojdbc8.jar'
jdbc_class_name = 'oracle.jdbc.OracleDriver'
url = 'jdbc:oracle:thin:@{0}:{1}:{2}'.format('127.0.0.1', '8080', 'orcl')
username = jyoracle_db_config['user']
password = jyoracle_db_config['password']
pool = OracleConnectionPool(jdbc_driver_path, jdbc_class_name, url, username, password)
executor = OracleQueryExecutor(pool)
# 获取连接并执行数据库操作
for i in range(1000):
try:
conn = pool.get_connection(timeout=10) # 设置获取连接的超时时间
try:
# 执行数据库操作
pass
querysqlstr = ''
executor.execute_query(querysqlstr)
finally:
# 关闭连接
pool.close_connection(conn)
except Exception as e:
write_log('initialize_pool', 'Failed to get connection{}'.format(e), ZTLOG_ERROR)
finally:
pool.close_pool()
优点:
1. 复用性:连接池可以重复使用数据库连接,避免频繁创建和关闭连接的开销,提高了数据库操作的效率。
2. 性能:连接池中的连接可以被多个线程共享,充分利用了系统资源,提供了更好的并发性能。
3. 控制连接数:连接池可以限制最大连接数,避免因为连接过多导致系统资源耗尽。
4. 自动管理连接:连接池封装了连接的获取和释放逻辑,使用者只需关注数据库操作,无需手动管理连接的创建和关闭。
5. 部署方便:不需要安装Oracle客户端软件,JayDeBeApi库使用JDBC驱动程序与Oracle数据库进行通信,避免了安装和配置Oracle客户端所涉及的复杂性和可能的兼容性问题。只需要确保正确配置了Java环境和所需的JDBC驱动程序,就可以使用JayDeBeApi连接Oracle数据库。
6. 可移植性:这种方式还可以降低依赖性,并使应用程序在不同平台上更易于移植和部署。你只需要将所需的JDBC驱动程序和相关的配置文件打包到应用程序中,并将其部署到目标环境即可。