mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-29 03:56:43 +08:00
62 lines
2.2 KiB
Python
62 lines
2.2 KiB
Python
"""旧 Oper 写入口的 SQLAlchemy 事务执行适配器。"""
|
|
|
|
from collections.abc import Awaitable, Callable
|
|
from contextlib import AbstractAsyncContextManager
|
|
from typing import TypeVar
|
|
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.db.uow import SqlAlchemyAsyncUnitOfWork, SqlAlchemyUnitOfWork
|
|
|
|
|
|
T = TypeVar("T")
|
|
|
|
|
|
class TransactionalWriteRunner:
|
|
"""为兼容写入口创建独占会话,并用 UoW 明确提交或回滚。"""
|
|
|
|
def __init__(
|
|
self,
|
|
*,
|
|
sync_session: Callable[[], Session],
|
|
async_session: Callable[[], AbstractAsyncContextManager[AsyncSession]],
|
|
) -> None:
|
|
"""保存同步会话工厂和异步会话上下文工厂。"""
|
|
self._sync_session = sync_session
|
|
self._async_session = async_session
|
|
|
|
def sync(self, operation: Callable[[Session], T]) -> T:
|
|
"""在独占同步 Session 中执行操作并统一收口事务。"""
|
|
session = self._sync_session()
|
|
# 兼容 Oper 历史上会返回刚写入的 ORM 对象;提交后若过期,Session 关闭后连主键
|
|
# 都无法读取。独占短会话没有后续一致性读取需求,因此保留已 flush 的字段快照。
|
|
session.expire_on_commit = False
|
|
unit_of_work = SqlAlchemyUnitOfWork(session)
|
|
try:
|
|
result = operation(session)
|
|
unit_of_work.commit()
|
|
return result
|
|
except Exception:
|
|
unit_of_work.rollback()
|
|
raise
|
|
finally:
|
|
session.close()
|
|
|
|
async def async_(
|
|
self,
|
|
operation: Callable[[AsyncSession], Awaitable[T]],
|
|
) -> T:
|
|
"""在独占 AsyncSession 中执行操作并统一收口事务。"""
|
|
async with self._async_session() as session:
|
|
# 与同步兼容入口保持相同的返回对象生命周期。
|
|
session.sync_session.expire_on_commit = False
|
|
unit_of_work = SqlAlchemyAsyncUnitOfWork(session)
|
|
try:
|
|
result = await operation(session)
|
|
await unit_of_work.commit()
|
|
return result
|
|
except Exception:
|
|
await unit_of_work.rollback()
|
|
raise
|