You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

102 lines
3.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2023/6/22 19:54
# @Author : old tom
# @File : dbengine.py
# @Project : futool-db-lite
# @Desc :
from urllib.parse import quote_plus as urlquote
from sqlalchemy import create_engine
from config.db_config import DbConfigLoader, DEFAULT_CONF_PATH
from session.session import SqlsessionFactory
from util.futool_lang import str_md5
class DatabaseEngineError(Exception):
def __init__(self, msg):
Exception.__init__(self, msg)
class ObjContainer(object):
# DatabaseEngine容器
engines = {}
# SqlsessionFactory容器
factory = {}
def has_obj(self, attr, k):
return k in getattr(self, attr)
def get_obj(self, attr, k):
return getattr(self, attr)[k]
def put_obj(self, attr, k, v):
getattr(self, attr)[k] = v
def remove_obj(self, attr, k):
del getattr(self, attr)[k]
def clean(self):
self.engines = {}
self.factory = {}
container = ObjContainer()
class DatabaseEngine(object):
"""
数据库连接
dialect+driver://username:password@host:port/database
mysql: mysql+pymysql://scott:tiger@localhost/foo
sqlserver: mssql+pymssql://scott:tiger@hostname:port/dbname
"""
DB_URL = {
'postgresql': 'postgresql+psycopg2://{0}:{1}@{2}:{3}/{4}',
# 使用thin客户端,不需要oracle client
'oracle': 'oracle+oracledb://{0}:{1}@{2}:{3}/?service_name={4}',
# pyodbc 不支持m1这里使用pymssql
'sqlserver': 'mssql+pymssql://{0}:{1}@{2}/{4}?charset=CP936'
}
# 连接池容器名称,具体看ObjContainer对象
attr = 'engines'
def __init__(self, db_name, conf_path=DEFAULT_CONF_PATH):
"""
pool_size:连接池大小
pool_recycle:连接回收(秒)
pool_pre_ping:测试连接执行select 1
参考 https://docs.sqlalchemy.org/en/20/core/pooling.html#connection-pool-configuration
"""
loader = DbConfigLoader(db_name, conf_path)
# 数据库配置
conf = loader.db_conf
if conf.dialect not in self.DB_URL:
raise DatabaseEngineError(msg='不支持的数据库类型')
# urlquote 处理密码中的特殊字符
url = self.DB_URL[conf.dialect].format(conf.user, urlquote(conf.passwd), conf.host, conf.port, conf.database)
# URL生成唯一ID
self.engine_id = str_md5(url)
# 根据数据源ID判断是否新建连接池
if container.has_obj(self.attr, self.engine_id):
self.engine = container.get_obj(self.attr, self.engine_id)
else:
engine = create_engine(url, pool_size=conf.pool_size, pool_recycle=conf.pool_recycle, pool_pre_ping=True,
echo=conf.show_sql)
container.put_obj(self.attr, self.engine_id, engine)
self.engine = engine
def create_session_factory(self):
"""
创建session工厂
相同数据库URL下全局只有一个SqlsessionFactory,除非有其他数据源
根据engine_id判断是否新建对象
:return:
"""
attr = 'factory'
if container.has_obj(attr, self.engine_id):
return container.get_obj(attr, self.engine_id)
else:
factory = SqlsessionFactory(self.engine)
container.put_obj(attr, self.engine_id, factory)
return factory