mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-11-02 21:34:32 +08:00
71 lines
2.3 KiB
Python
71 lines
2.3 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
|