mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-04-13 10:29:50 +08:00
添加异步数据库支持,更新相关模型和会话管理
This commit is contained in:
@@ -1,171 +0,0 @@
|
||||
# 异步数据库操作指南
|
||||
|
||||
## 概述
|
||||
|
||||
本指南介绍如何在MoviePilot项目中实现异步数据库操作,而无需重写现有的同步数据库模块。
|
||||
|
||||
## 方案优势
|
||||
|
||||
1. **最小化改动**: 不需要重写现有的同步数据库操作代码
|
||||
2. **渐进式迁移**: 可以逐步将需要异步的操作迁移到异步版本
|
||||
3. **向后兼容**: 现有的同步代码继续正常工作
|
||||
4. **性能提升**: 通过线程池执行同步数据库操作,避免阻塞事件循环
|
||||
|
||||
## 核心组件
|
||||
|
||||
### 1. 异步适配器 (`app/db/async_adapter.py`)
|
||||
|
||||
提供以下功能:
|
||||
- `async_db_operation`: 将同步函数包装为异步函数
|
||||
- `async_db_session`: 为异步操作提供数据库会话
|
||||
- `AsyncDbOper`: 异步数据库操作基类
|
||||
- `to_async_db_oper`: 将同步操作类转换为异步版本
|
||||
- `AsyncDbSession`: 异步数据库会话上下文管理器
|
||||
|
||||
### 2. 异步操作类 (`app/db/async_user_oper.py`)
|
||||
|
||||
展示如何创建异步版本的数据库操作类。
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 方法1: 使用装饰器自动转换
|
||||
|
||||
```python
|
||||
from app.db.user_oper import UserOper
|
||||
from app.db.async_adapter import to_async_db_oper
|
||||
|
||||
# 自动将同步类转换为异步版本
|
||||
AsyncUserOper = to_async_db_oper(UserOper)
|
||||
|
||||
# 使用异步版本
|
||||
async def example():
|
||||
async_user_oper = AsyncUserOper()
|
||||
users = await async_user_oper.list()
|
||||
return users
|
||||
```
|
||||
|
||||
### 方法2: 手动创建异步方法
|
||||
|
||||
```python
|
||||
from app.db.async_adapter import async_db_operation
|
||||
|
||||
class AsyncUserOperManual:
|
||||
def __init__(self, db: Session = None):
|
||||
self._sync_oper = UserOper(db)
|
||||
|
||||
@async_db_operation
|
||||
def list(self) -> List[User]:
|
||||
return self._sync_oper.list()
|
||||
|
||||
@async_db_operation
|
||||
def add(self, **kwargs):
|
||||
return self._sync_oper.add(**kwargs)
|
||||
```
|
||||
|
||||
### 方法3: 使用异步上下文管理器
|
||||
|
||||
```python
|
||||
from app.db.async_adapter import AsyncDbSession
|
||||
|
||||
async def example():
|
||||
async with AsyncDbSession() as db:
|
||||
# 直接使用同步操作,但在线程池中执行
|
||||
from functools import partial
|
||||
users = await asyncio.get_event_loop().run_in_executor(
|
||||
None, partial(lambda db: db.query(User).all(), db)
|
||||
)
|
||||
return users
|
||||
```
|
||||
|
||||
### 方法4: 装饰器包装单个函数
|
||||
|
||||
```python
|
||||
from app.db.async_adapter import async_db_operation
|
||||
|
||||
@async_db_operation
|
||||
def get_user_by_name_sync(db: Session, name: str) -> User:
|
||||
return db.query(User).filter(User.name == name).first()
|
||||
|
||||
async def example():
|
||||
async with AsyncDbSession() as db:
|
||||
user = await get_user_by_name_sync(db, "admin")
|
||||
return user
|
||||
```
|
||||
|
||||
## 在FastAPI中使用
|
||||
|
||||
### 依赖注入
|
||||
|
||||
```python
|
||||
async def get_current_user_async_dependency(
|
||||
token_data: schemas.TokenPayload = Depends(verify_token)
|
||||
) -> User:
|
||||
async with AsyncDbSession() as db:
|
||||
from functools import partial
|
||||
user = await asyncio.get_event_loop().run_in_executor(
|
||||
None, partial(User.get, db, rid=token_data.sub)
|
||||
)
|
||||
if not user:
|
||||
raise HTTPException(status_code=403, detail="用户不存在")
|
||||
return user
|
||||
|
||||
@router.get("/me/async")
|
||||
async def get_current_user_async(
|
||||
current_user: User = Depends(get_current_user_async_dependency)
|
||||
):
|
||||
return current_user
|
||||
```
|
||||
|
||||
### API端点
|
||||
|
||||
```python
|
||||
@router.get("/users/async")
|
||||
async def get_users_async():
|
||||
async_user_oper = AsyncUserOper()
|
||||
users = await async_user_oper.list()
|
||||
return users
|
||||
```
|
||||
|
||||
## 并发操作
|
||||
|
||||
### 批量操作
|
||||
|
||||
```python
|
||||
@router.post("/users/batch-async")
|
||||
async def create_users_batch_async(users_data: List[schemas.UserCreate]):
|
||||
async_user_oper = AsyncUserOper()
|
||||
|
||||
# 并发创建用户
|
||||
tasks = []
|
||||
for user_data in users_data:
|
||||
task = async_user_oper.add(**user_data.dict())
|
||||
tasks.append(task)
|
||||
|
||||
# 等待所有任务完成
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
# 获取创建的用户列表
|
||||
all_users = await async_user_oper.list()
|
||||
return all_users[-len(users_data):]
|
||||
```
|
||||
|
||||
### 复杂查询
|
||||
|
||||
```python
|
||||
@router.get("/users/stats/async")
|
||||
async def get_user_stats_async():
|
||||
async_user_oper = AsyncUserOper()
|
||||
|
||||
# 并发执行多个数据库查询
|
||||
users_task = async_user_oper.list()
|
||||
active_users_task = async_user_oper.get_active_users()
|
||||
|
||||
# 等待所有查询完成
|
||||
users, active_users = await asyncio.gather(users_task, active_users_task)
|
||||
|
||||
return {
|
||||
"total_users": len(users),
|
||||
"active_users": len(active_users),
|
||||
"inactive_users": len(users) - len(active_users)
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user