Страницы

Поиск по вопросам

суббота, 11 апреля 2020 г.

Работа сайта на SQLAlchemy остановилась из-за одной случайной ошибки. Правильно ли я работаю с сессиями?

#python #sqlalchemy

                    
Есть сайт на Flask, SQLAlchemy, PostgreSQL. При создании новой записи случилась ошибка,
что PK ключ этой таблицы уже занят. Обычная таблица, с id SERIAL PRIMARY KEY. id генерятся
всегда только автоматически.

И вот после этой ошибки каждое обращение к базе данных, даже просто на чтение, падало
с такой ошибкой:


  sqlalchemy.exc.InvalidRequestError: This Session's transaction has been rolled
back due to a previous exception during flush. To begin a new transaction with this
Session, first issue Session.rollback(). Original exception was: (raised as a result
of Query-invoked autoflush; consider using a session.no_autoflush block if this flush
is occurring prematurely) (psycopg2.IntegrityError) duplicate key value violates unique
constraint "my_table_pkey"


До этого в этом сайте я использовал Flask-SQLAlchemy, таких проблем никогда не было.
Но после перехода просто на ванильный SQLAlchemy, ошибка эта случилась. 

Работа с бд ведется через db_session, который определен в __init__.py модуля:

_engine = create_engine(c.DATABASE_URL)
_Session = sessionmaker(bind=_engine)
db_session = _Session()


Создание записей делаю через db_session.add(new_ojb); db_session.commit()

Видите вы в такой работе с SQLAlchemy что-то неправильное? Почему при создании записи
в таблице появился дубль PK, почему потом последующие запросы из-за этой ошибки перестали
обрабатываться?
    


Ответы

Ответ 1



Ошибка происходит из-за того, что предыдущая транзакция не была откачена. Для того чтобы ее откатить достаточно сделать session.rollback(). Обычно комитят изменения в алхимии следующим образом: try: session.commit() except DatabaseError, e: session.rollback() logger.error('...') Обновление session.flush() записывает изменения в базу, но не коммитит их, они считаются не персистентными (но видны, например, уже при запросах в базу внутри этой транзакции), то есть если после этого будет сделан session.rollback() они пропадут. Вот есть еще пост по этому поводу с комментарием от создателя алхимии. Обновление 2 Ловить исключения надо в любом случае, иначе алхимия будет тебе выкидывать такую ошибку, и это абсолютно правильно c её стороны. Ты можешь эти ситуации обрабатывать явно через try/except, через менеджер контекста либо декоратор, выбирай что по вкусу. :) По поводу ошибки генерации ID, теоретически они могут возникнуть при таком кейсе, смотри секцию подводные камни. Это всё что я могу сказать, глядя на приведённые данные. Для подстраховки от возникновения такой ошибки снова ты можешь сделать 2 вещи, нигде не выполнять INSERT с заранее переданным PK и поставить на этой таблице setval на самый большой текущий PK. Подробнее.

Комментариев нет:

Отправить комментарий