327 lines
9.9 KiB
Markdown
327 lines
9.9 KiB
Markdown
以下是为提供的 Python 代码编写的 **Markdown 格式技术文档**,涵盖了模块功能、类说明、函数接口、使用方式及关键设计思想。
|
||
|
||
---
|
||
|
||
# `dbor` 模块技术文档
|
||
|
||
> 数据库操作抽象层与连接池管理(支持同步/异步)
|
||
|
||
## 概述
|
||
|
||
`dbor` 是一个轻量级的数据库操作抽象框架,提供统一接口访问多种数据库(如 MySQL、PostgreSQL、SQLite、Oracle、SQL Server),并支持 **同步与异步模式**。该模块通过工厂模式创建数据库适配器,并结合连接池机制提升性能和资源利用率。
|
||
|
||
主要特性:
|
||
- 支持主流关系型数据库
|
||
- 同步与异步双模式运行
|
||
- 自动连接池管理
|
||
- 单例全局数据库池控制器
|
||
- 配置驱动式数据库接入
|
||
- 安全密码解密(RC4)
|
||
- 上下文管理器自动提交/回滚
|
||
|
||
---
|
||
|
||
## 依赖说明
|
||
|
||
```python
|
||
import asyncio
|
||
from functools import wraps
|
||
from contextlib import asynccontextmanager
|
||
import threading
|
||
```
|
||
|
||
自定义模块依赖(需确保路径正确):
|
||
- `appPublic.myImport`:动态导入模块
|
||
- `appPublic.dictObject`:字典对象封装
|
||
- `appPublic.Singleton`:单例装饰器
|
||
- `appPublic.myjson.loadf`:加载 JSON 文件
|
||
- `appPublic.jsonConfig.getConfig`:配置读取
|
||
- `appPublic.rc4.unpassword`:RC4 密码解密
|
||
- `appPublic.log.exception`:异常日志记录
|
||
|
||
---
|
||
|
||
## 核心组件
|
||
|
||
### 1. `sqlorFactory(dbdesc) → SQLor`
|
||
|
||
根据数据库描述信息实例化对应的数据库操作对象。
|
||
|
||
#### 参数
|
||
| 参数名 | 类型 | 说明 |
|
||
|--------|--------|----|
|
||
| `dbdesc` | `dict` | 数据库配置字典,必须包含 `'driver'` 字段 |
|
||
|
||
#### 返回值
|
||
- 继承自 `SQLor` 的具体数据库操作实例(如 `MySqlor`, `AioMysqlor` 等)
|
||
- 若未匹配到子类,则返回基础 `SQLor` 实例
|
||
|
||
#### 示例配置结构
|
||
```python
|
||
{
|
||
"driver": "mysql.connector",
|
||
"async_mode": False,
|
||
"kwargs": {
|
||
"host": "localhost",
|
||
"user": "root",
|
||
"password": "enc:xxxxx", # RC4 加密后的密码
|
||
"database": "testdb"
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 2. `sqlorFromFile(dbdef_file, coding='utf8') → SQLor`
|
||
|
||
从 JSON 配置文件加载数据库定义并生成对应操作实例。
|
||
|
||
#### 参数
|
||
| 参数名 | 类型 | 默认值 | 说明 |
|
||
|------------|--------|--------|----|
|
||
| `dbdef_file` | `str` | - | JSON 配置文件路径 |
|
||
| `coding` | `str` | `'utf8'` | 文件编码格式 |
|
||
|
||
#### 示例
|
||
```python
|
||
sor = sqlorFromFile('/path/to/db.json')
|
||
```
|
||
|
||
---
|
||
|
||
## 连接生命周期管理:`LifeConnect`
|
||
|
||
封装单个数据库连接的生命周期控制,包括健康检测、重连机制、使用计数等。
|
||
|
||
### 构造函数
|
||
```python
|
||
LifeConnect(connfunc, kw, use_max=1000, async_mode=False)
|
||
```
|
||
|
||
| 参数 | 类型 | 说明 |
|
||
|------------|----------|----|
|
||
| `connfunc` | `callable` | 创建连接的函数(如 `sqlite3.connect`) |
|
||
| `kw` | `dict` | 连接参数 |
|
||
| `use_max` | `int` | 最大使用次数后关闭连接,默认 `1000` |
|
||
| `async_mode` | `bool` | 是否异步模式 |
|
||
|
||
### 方法
|
||
|
||
| 方法名 | 异步 | 说明 |
|
||
|------------|------|----|
|
||
| `use()` | ✅ | 获取可用连接,失败时尝试重建 |
|
||
| `free(conn)`| ✅ | 释放连接(暂未启用最大使用限制逻辑) |
|
||
| `testok()` | ✅ | 测试连接是否正常(执行 `SELECT 1`) |
|
||
| `_mkconn()` | ✅ | 内部方法:创建新连接 |
|
||
|
||
> ⚠️ 注意:当前 `free()` 中关于 `use_cnt >= use_max` 的判断被注释,不会触发自动关闭。
|
||
|
||
---
|
||
|
||
## 连接池:`ConnectionPool`
|
||
|
||
管理某一数据库的所有连接,实现连接复用。
|
||
|
||
### 构造函数
|
||
```python
|
||
ConnectionPool(dbdesc, loop)
|
||
```
|
||
|
||
| 参数 | 类型 | 说明 |
|
||
|----------|---------------|----|
|
||
| `dbdesc` | `dict` | 数据库配置 |
|
||
| `loop` | `asyncio.EventLoop` | 异步事件循环 |
|
||
|
||
### 属性
|
||
| 属性 | 类型 | 说明 |
|
||
|--------------|------------------|----|
|
||
| `maxconn` | `int` | 最大连接数(默认 5) |
|
||
| `maxuse` | `int` | 每连接最大使用次数 |
|
||
| `_pool` | `asyncio.Queue` | 存放 `LifeConnect` 实例的队列 |
|
||
| `connectObject`| `dict` | 当前活跃连接映射表 |
|
||
|
||
### 方法
|
||
|
||
| 方法 | 异步 | 说明 |
|
||
|----------------|------|----|
|
||
| `connect()` | ✅ | 创建一个 `LifeConnect` 并放入池中 |
|
||
| `aquire()` | ✅ | 从池中获取可用连接 |
|
||
| `release(conn)` | ✅ | 释放连接回池 |
|
||
| `isEmpty()` | ❌ | 判断池是否为空 |
|
||
| `isFull()` | ❌ | 判断池是否已满 |
|
||
| `_fillPool()` | ✅ | 初始化填充连接池至最大容量 |
|
||
|
||
> 📝 注:目前 `_fillPool()` 调用后并未实际等待完成,存在潜在问题。
|
||
|
||
---
|
||
|
||
## 全局数据库池管理器:`DBPools`(单例)
|
||
|
||
使用 `@SingletonDecorator` 装饰,保证全局唯一实例,统一管理多个数据库连接池。
|
||
|
||
### 构造函数
|
||
```python
|
||
DBPools(databases={}, max_connect=100, loop=None)
|
||
```
|
||
|
||
| 参数 | 类型 | 说明 |
|
||
|--------------|--------|----|
|
||
| `databases` | `dict` | 数据库名称 → 配置字典的映射 |
|
||
| `max_connect` | `int` | 全局最大并发连接数限制 |
|
||
| `loop` | `EventLoop` | 可选事件循环 |
|
||
|
||
### 属性
|
||
| 属性 | 类型 | 说明 |
|
||
|-------------|-------------------|----|
|
||
| `sema` | `asyncio.Semaphore` | 控制总连接数信号量 |
|
||
| `_cpools` | `dict` | 数据库名 → `ConnectionPool` 映射 |
|
||
| `databases` | `dict` | 所有注册数据库配置 |
|
||
| `meta` | `dict` | 预留元数据存储 |
|
||
| `e_except` | `Exception` | 上下文中捕获的异常 |
|
||
|
||
---
|
||
|
||
### 核心方法
|
||
|
||
#### `addDatabase(name, desc)`
|
||
注册新的数据库配置。
|
||
|
||
```python
|
||
dbpools.addDatabase('devdb', {
|
||
'driver': 'aiomysql',
|
||
'async_mode': True,
|
||
'kwargs': { ... }
|
||
})
|
||
```
|
||
|
||
#### `get_dbname(name) → str or None`
|
||
获取数据库逻辑名对应的实际数据库名(`dbname`),若无则返回 `None`。
|
||
|
||
#### `isAsyncDriver(dbname) → bool`
|
||
判断指定数据库是否运行在异步模式下。
|
||
|
||
#### `getSqlor(name) → SQLor`
|
||
获取指定数据库的操作对象(含连接和游标)。
|
||
|
||
- 使用信号量控制并发
|
||
- 自动建立底层连接与游标
|
||
- 返回已绑定连接的 `SQLor` 实例
|
||
|
||
#### `freeSqlor(sor)`
|
||
释放由 `getSqlor()` 获取的 `SQLor` 实例,归还连接并释放信号量。
|
||
|
||
#### `sqlorContext(name)`
|
||
**异步上下文管理器**,推荐使用的安全访问方式。
|
||
|
||
```python
|
||
async with dbpools.sqlorContext('mydb') as sor:
|
||
await sor.execute('SELECT * FROM users')
|
||
result = await sor.fetchall()
|
||
# 自动 commit
|
||
```
|
||
|
||
##### 行为逻辑
|
||
- 成功退出:自动提交事务(如果 `dataChanged == True`)
|
||
- 抛出异常:记录日志 + 回滚事务(如有更改)
|
||
- 始终执行:释放连接资源
|
||
|
||
---
|
||
|
||
### 内部方法(不建议直接调用)
|
||
|
||
| 方法 | 异步 | 说明 |
|
||
|--------------------|------|----|
|
||
| `_aquireConn(dbname)` | ✅ | 获取连接、游标三元组 `(async_mode, conn, cur)` |
|
||
| `_releaseConn(...)` | ✅ | 关闭游标与连接,归还至池 |
|
||
|
||
> 🔐 密码处理:在 `_aquireConn` 中自动调用 `unpassword(pw)` 解密。
|
||
|
||
---
|
||
|
||
## 支持的数据库驱动
|
||
|
||
| 驱动模块 | 同步类 | 异步类 | 支持情况 |
|
||
|---------------------|----------------|------------------|-------|
|
||
| `sqlite3` | `SQLite3or` | `Aiosqliteor` | ✅ |
|
||
| `mysql.connector` | `MySqlor` | `AioMysqlor` | ✅ |
|
||
| `psycopg2` / `asyncpg` | `SQLor` 扩展 | `AioPostgresqlor`| ✅ |
|
||
| `cx_Oracle` | `Oracleor` | (暂无异步) | ✅ |
|
||
| `pyodbc` / `pymssql`| `SQLor` 扩展 | `MsSqlor` | ✅ |
|
||
|
||
> 💡 提示:所有驱动需继承 `SQLor` 并实现 `isMe(driver_name)` 类方法用于识别。
|
||
|
||
---
|
||
|
||
## 使用示例
|
||
|
||
### 步骤 1:初始化 DBPools(应用启动时)
|
||
|
||
```python
|
||
from appPublic.jsonConfig import getConfig
|
||
from your_module import DBPools
|
||
|
||
config = getConfig() # 加载全局配置
|
||
dbpools = DBPools(databases=config.databases, loop=asyncio.get_event_loop())
|
||
```
|
||
|
||
### 步骤 2:使用上下文访问数据库
|
||
|
||
```python
|
||
async def fetch_users():
|
||
async with dbpools.sqlorContext('users_db') as sor:
|
||
await sor.execute('SELECT id, name FROM users LIMIT 10')
|
||
rows = await sor.fetchall()
|
||
return rows
|
||
```
|
||
|
||
### 步骤 3:手动获取/释放(高级用法)
|
||
|
||
```python
|
||
async def manual_usage():
|
||
sor = await dbpools.getSqlor('reporting')
|
||
try:
|
||
await sor.execute('UPDATE stats SET processed=1 WHERE flag=0')
|
||
await sor.commit()
|
||
except:
|
||
await sor.rollback()
|
||
finally:
|
||
await dbpools.freeSqlor(sor)
|
||
```
|
||
|
||
---
|
||
|
||
## 安全与日志
|
||
|
||
- 所有密码字段通过 `unpassword()` 解密(基于 RC4)
|
||
- 异常通过 `appPublic.log.exception()` 记录堆栈
|
||
- 上下文管理器自动处理事务完整性
|
||
|
||
---
|
||
|
||
## 已知问题与改进建议
|
||
|
||
| 问题 | 描述 | 建议 |
|
||
|-----|------|------|
|
||
| `free()` 方法中 `use_max` 逻辑被注释 | 连接无法按使用次数回收 | 恢复条件判断逻辑 |
|
||
| `_fillPool()` 未 await 循环 | 初始连接可能未完全建立 | 改为批量 `asyncio.gather()` |
|
||
| `lock` 相关代码被注释 | 缺少并发保护 | 若多线程需启用锁机制 |
|
||
| `print()` 方法仅调试用途 | 应移除或改为日志输出 | 删除或替换为 logger.debug |
|
||
|
||
---
|
||
|
||
## 总结
|
||
|
||
`dbor` 提供了一个灵活、可扩展的数据库访问架构,适用于中小型项目中的多数据库统一管理场景。其核心优势在于:
|
||
|
||
✅ 统一接口
|
||
✅ 异步友好
|
||
✅ 自动资源管理
|
||
✅ 安全配置支持
|
||
|
||
适合集成进 Web 框架(如 FastAPI、Tornado)或后台服务系统中作为 ORM 替代方案。
|
||
|
||
---
|
||
|
||
> 文档版本:v1.0
|
||
> 编写时间:2025年4月5日
|
||
> 适用代码版本:请以实际提交为准 |