Не удается поймать SQLAlchemy IntegrityError
Попытайтесь, как я мог, я не могу правильно поймать sqlalchemy IntegrityError:
from sqlalchemy import exc
try:
insert_record()
except exc.IntegrityError, exc:
print exc # this is never called
handle_elegantly() # this is never called
Как и следовало ожидать:
IntegrityError: (IntegrityError) insert or update on table "my_table"
violates foreign key constraint "my_table_some_column_fkey"
Я попытался явно:
from sqlalchemy.exc import IntegrityError
UPDATE:
Я нашел что-то похожее на то, что происходит здесь, где Integrity Error не выбрасывается до тех пор, пока сеанс не будет сброшен на db, а после выполнения блоков try
/except
: Попытка поймать ошибку целостности с помощью SQLAlchemy
Однако добавление session.flush()
в блок try
дает InvalidRequestError
:
ERROR:root:This Session 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: (IntegrityError)
Ответы
Ответ 1
У меня такая же потребность в моем приложении Flask, я обрабатываю его, как показано ниже, и он работает:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import exc
db = SQLAlchemy(Flask(__name__))
try:
db.session.add(resource)
return db.session.commit()
except exc.IntegrityError as e:
db.session().rollback()
Ответ 2
Как только IntegrityError
будет поднят, независимо от того, поймала ли вы ошибку, сеанс, в котором вы работали, недействителен. Поскольку второе сообщение об ошибке инструктирует вас, To begin a new transaction with this Session, first issue Session.rollback().
, чтобы продолжить использование сеанса, вам нужно выпустить session.rollback()
Я не могу сказать точно, но я предполагаю, что вы или ваша веб-инфраструктура пытаетесь продолжить использование сеанса, который каким-то образом поднял IntegrityError. Я рекомендую вам выпустить session.rollback()
либо после того, как вы поймаете исключение, либо в своей функции handle_elegantly
.
Если вы запустите ниже, вы увидите, что я имею в виду:
from sqlalchemy import types
from sqlalchemy import exc
from sqlalchemy import create_engine
from sqlalchemy.schema import Column
from zope.sqlalchemy import ZopeTransactionExtension
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, scoped_session
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
name = Column(types.String, primary_key=True)
def handle_elegantly(name):
session = DBSession()
session.add(User(name=name))
session.flush()
print 'Exception elegantly handled!!\n'
def pretend_view(request):
"""Pretend view in a Pyramid application using pyramid_tm"""
session = DBSession()
user = User()
print '\n-------Here we rollback before continuing -------'
try:
session.add(user)
session.flush()
except exc.IntegrityError:
session.rollback()
handle_elegantly('This will run fine')
print '\n------- Here we do not, and this will error -------'
try:
session.add(user)
session.flush()
except exc.IntegrityError:
handle_elegantly('Exception will be raised')
if __name__ == '__main__':
engine = create_engine('sqlite://')
global DBSession
DBSession = scoped_session(
sessionmaker(extension=ZopeTransactionExtension()))
DBSession.configure(bind=engine)
Base.metadata.bind = engine
Base.metadata.create_all()
pretend_view("dummy request")
Ответ 3
SQLALCHEMY_COMMIT_ON_TEARDOWN = False