РЕПЕТИТОР математика физика информатика
Для школьников и студентов. Подтягивание пробелов. ЦЭ, ЦТ, ОГЭ, ЕГЭ.
Идет набор на ЛЕТО. Жмите для подробностей:)
696 of 711 menu

Исключение StaleDataError

Исключение StaleDataError наследуется от SQLAlchemyError и возбуждается ORM-сессией, когда операция UPDATE или DELETE не затронула ни одной строки. Это означает, что данные в базе изменились с момента последнего чтения объекта в текущей сессии. Обычно такое поведение связано с параллельным доступом: другая транзакция изменила или удалила запись раньше нас. SQLAlchemy сравнивает количество ожидаемых и реально изменённых строк и сигнализирует о рассинхронизации через StaleDataError.

Синтаксис

from sqlalchemy.orm.exc import StaleDataError

Пример

Давайте создадим объект, сохраним его, а затем удалим строку напрямую через SQL. При повторном сохранении объекта ORM обнаружит, что строка больше не существует, и возбудит исключение:

from sqlalchemy import create_engine, text from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session from sqlalchemy.orm.exc import StaleDataError class Base(DeclarativeBase): pass class Article(Base): __tablename__ = 'articles' id: Mapped[int] = mapped_column(primary_key=True) title: Mapped[str] engine = create_engine('sqlite:///:memory:') Base.metadata.create_all(engine) with Session(engine) as session: article = Article(title='article') session.add(article) session.commit() # delete the row directly, bypassing ORM with engine.connect() as conn: conn.execute(text('DELETE FROM articles WHERE id = :id'), {'id': article.id}) conn.commit() article.title = 'article updated' try: session.commit() except StaleDataError as exc: print(type(exc).__name__) session.rollback()

Результат выполнения кода:

"StaleDataError"

Пример

Давайте смоделируем параллельное изменение: одна сессия читает объект, вторая меняет его и коммитит, после чего первая сессия пытается записать устаревшие данные:

from sqlalchemy import create_engine from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session from sqlalchemy.orm.exc import StaleDataError class Base(DeclarativeBase): pass class Article(Base): __tablename__ = 'articles' id: Mapped[int] = mapped_column(primary_key=True) title: Mapped[str] num: Mapped[int] engine = create_engine('sqlite:///:memory:') Base.metadata.create_all(engine) with Session(engine) as session: article = Article(title='article', num=1) session.add(article) session.commit() article_id = article.id with Session(engine) as session_a, Session(engine) as session_b: a = session_a.get(Article, article_id) b = session_b.get(Article, article_id) b.title = 'article' b.num = 2 session_b.commit() a.num = 3 try: session_a.commit() except StaleDataError as exc: print(type(exc).__name__) session_a.rollback()

Результат выполнения кода:

"StaleDataError"

Пример

Давайте включим оптимистичную блокировку через параметр version_id_col и посмотрим, как устаревшая версия объекта приводит к исключению:

from sqlalchemy import create_engine from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session from sqlalchemy.orm.exc import StaleDataError class Base(DeclarativeBase): pass class Article(Base): __tablename__ = 'articles' id: Mapped[int] = mapped_column(primary_key=True) title: Mapped[str] version_id: Mapped[int] = mapped_column(nullable=False) __mapper_args__ = {'version_id_col': version_id} engine = create_engine('sqlite:///:memory:') Base.metadata.create_all(engine) with Session(engine) as session: article = Article(title='article', version_id=1) session.add(article) session.commit() article_id = article.id with Session(engine) as session_a, Session(engine) as session_b: a = session_a.get(Article, article_id) b = session_b.get(Article, article_id) b.title = 'article' session_b.commit() a.title = 'article updated' try: session_a.commit() except StaleDataError as exc: print(type(exc).__name__) session_a.rollback()

Результат выполнения кода:

"StaleDataError"

Смотрите также

  • исключение SQLAlchemyError,
    которое является базовым для всех ошибок SQLAlchemy
  • исключение InvalidRequestError,
    которое сигнализирует о некорректном запросе к сессии
  • исключение FlushError,
    которое возникает при проблемах во время flush сессии
  • исключение ObjectDeletedError,
    которое возбуждается при обращении к удалённому объекту
Мы используем cookie для работы сайта, аналитики и персонализации. Обработка данных происходит согласно Политике конфиденциальности.
принять все настроить отклонить