mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-03-25 06:21:23 +08:00
171 lines
4.4 KiB
Markdown
171 lines
4.4 KiB
Markdown
# 异步数据库操作指南
|
||
|
||
## 概述
|
||
|
||
本指南介绍如何在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)
|
||
}
|
||
``` |