Метод begin_nested
Метод begin_nested класса AsyncSession
создает вложенную транзакцию, также известную
как SAVEPOINT. Вложенная транзакция позволяет
выполнить группу операций и при необходимости
откатить только их, не затрагивая внешнюю
транзакцию. Метод не принимает обязательных
параметров и возвращает объект
AsyncSessionTransaction, который можно
использовать как асинхронный контекстный
менеджер.
Вложенная транзакция работает поверх уже открытой транзакции. Если внешняя транзакция еще не начата, SQLAlchemy начнет ее автоматически. При выходе из блока без ошибок вложенная транзакция фиксируется через RELEASE SAVEPOINT, а при возникновении исключения выполняется ROLLBACK TO SAVEPOINT.
Синтаксис
await session.begin_nested()
Пример
Давайте откроем вложенную транзакцию и добавим запись, а затем зафиксируем только вложенную транзакцию:
import asyncio
from sqlalchemy import String
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column(String(100))
status: Mapped[str] = mapped_column(String(50))
async def main():
engine = create_async_engine('sqlite+aiosqlite:///:memory:')
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
async with AsyncSession(engine) as session:
async with session.begin_nested():
session.add(Article(title='article 1', status='new'))
await session.commit()
res = await session.get(Article, 1)
print(res.title)
await engine.dispose()
asyncio.run(main())
Результат выполнения кода:
"article 1"
Пример
Давайте откатим вложенную транзакцию, чтобы сохранить изменения внешней транзакции:
import asyncio
from sqlalchemy import String, select
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column(String(100))
status: Mapped[str] = mapped_column(String(50))
async def main():
engine = create_async_engine('sqlite+aiosqlite:///:memory:')
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
async with AsyncSession(engine) as session:
session.add(Article(title='article 1', status='new'))
try:
async with session.begin_nested():
session.add(Article(title='article 2', status='new'))
raise ValueError('rollback nested')
except ValueError:
pass
await session.commit()
res = await session.execute(select(Article))
print([a.title for a in res.scalars().all()])
await engine.dispose()
asyncio.run(main())
Результат выполнения кода:
['article 1']
Пример
Давайте используем метод begin_nested без
контекстного менеджера и явно вызовем
commit и rollback:
import asyncio
from sqlalchemy import String
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column(String(100))
status: Mapped[str] = mapped_column(String(50))
async def main():
engine = create_async_engine('sqlite+aiosqlite:///:memory:')
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
async with AsyncSession(engine) as session:
nested = await session.begin_nested()
session.add(Article(title='article 1', status='new'))
await nested.commit()
nested = await session.begin_nested()
session.add(Article(title='article 2', status='draft'))
await nested.rollback()
await session.commit()
res = await session.get(Article, 1)
print(res.title)
await engine.dispose()
asyncio.run(main())
Результат выполнения кода:
"article 1"
Смотрите также
-
класс
AsyncSession,
который представляет асинхронную сессию -
метод
begin,
который открывает внешнюю транзакцию -
метод
commit,
который фиксирует текущую транзакцию -
метод
rollback,
который откатывает текущую транзакцию