Как сессии SQLAlchemy использовать внешнюю транзакцию?

Ссылка скопирована
1 ответ

Пытаюсь сделать декоратор, которой бы оборачивал вьюху 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

Нужно решить такую задачу?

Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.

Заказать помощь
Лучший ответ
1
Мария Код Ответ

Для использования сессий 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()

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 внутри внешней транзакции для обеспечения целостности данных и избежания проблем с параллельными транзакциями.

Другие ответы (0)

Пока нет других ответов. Будьте первым, кто поможет автору.

Ответить на вопрос

комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Вам также может быть интересно