Как сессии SQLAlchemy использовать внешнюю транзакцию?
Пытаюсь сделать декоратор, которой бы оборачивал вьюху FastAPI и который бы открывал и закрывал транзакцию SQLAlchemy. Делаю так:
from fastapi import FastAPI from sqlalchemy import MetaData from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker from sqlalchemy.orm import declarative_base app = FastAPI() engine = create_async_engine("url", echo=True) session_factory = async_sessionmaker(bind=engine, expire_on_commit=False, autocommit=False, autoflush=False) metadata = MetaData() Base = declarative_base(metadata=metadata) def transaction(view): @wraps(view) async def wrapper(*args, **kwargs): async with engine.begin(): result = await view(*args, **kwargs) return result return wrapper class Partner(Base): """Поставщик (контрагент).""" __tablename__ = "partners" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), default=uuid.uuid4, primary_key=True, index=True) organization_name: Mapped[str] @app.get('/') @transaction async def index(): session = session_factory() partner = Partner(organization_name="Partner Name") session.add(partner) await session.flush() await session.refresh(partner) return {'partner_id': partner.id} |
from fastapi import FastAPI from sqlalchemy import MetaData from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker from sqlalchemy.orm import declarative_base app = FastAPI() engine = create_async_engine("url", echo=True) session_factory = async_sessionmaker(bind=engine, expire_on_commit=False, autocommit=False, autoflush=False) metadata = MetaData() Base = declarative_base(metadata=metadata) def transaction(view): @wraps(view) async def wrapper(*args, **kwargs): async with engine.begin(): result = await view(*args, **kwargs) return result return wrapper class Partner(Base): """Поставщик (контрагент).""" __tablename__ = "partners" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), default=uuid.uuid4, primary_key=True, index=True) organization_name: Mapped[str] @app.get('/') @transaction async def index(): session = session_factory() partner = Partner(organization_name="Partner Name") session.add(partner) await session.flush() await session.refresh(partner) return {'partner_id': partner.id}
Транзакция в декораторе transaction открывается, однако, изменения не попадает в нее. Вместо этого они попадают в транзакцию сессии. Я вроде где то видел, что если есть уже открытая транзакция, то сессия пишет в нее, но не смог сделать так.
Как сделать так, чтобы сессия писала в транзакцию, которая была открыта в декораторе?
Дополнительно:
а зачем так извращаться, зачем делать две сущности, одну через transaction, вторую в session? и вообще в FastAPI принято один раз что-то типа твоего session, явно передавать в параметрах функции через Depends
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос
Для использования сессий SQLAlchemy внутри внешней транзакции, вам необходимо создать объект сессии и начать транзакцию вручную. Вот пример кода на языке Python с использованием SQLAlchemy:
from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker # Создаем объект сессии engine = create_engine('sqlite:///example.db') Session = sessionmaker(bind=engine) session = Session() # Начинаем внешнюю транзакцию transaction = session.begin_nested() try: # Выполняем операции с базой данных # Например, добавляем новую запись new_record = MyModel(name='example') session.add(new_record) # Коммитим изменения session.commit() # Фиксируем внешнюю транзакцию transaction.commit() except: # Если произошла ошибка, откатываем изменения session.rollback() # Откатываем также и внешнюю транзакцию transaction.rollback() finally: # Закрываем сессию session.close()
В данном примере мы создаем объект сессии, начинаем внешнюю транзакцию с помощью метода `begin_nested()`, выполним операции с базой данных внутри этой транзакции, коммитим изменения, и фиксируем внешнюю транзакцию. В случае возникновения ошибки, откатываем изменения и внешнюю транзакцию.
Таким образом, вы можете использовать сессии SQLAlchemy внутри внешней транзакции для обеспечения целостности данных и избежания проблем с параллельными транзакциями.