Python 无法捕获 SQLAlchemy IntegrityError
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24522290/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
cannot catch SQLAlchemy IntegrityError
提问by Chrispy
Try as I might, I can't seem to catch the sqlalchemy IntegrityError correctly:
尽我所能,我似乎无法正确捕获 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
As what one might expect:
正如人们所期望的那样:
IntegrityError: (IntegrityError) insert or update on table "my_table"
violates foreign key constraint "my_table_some_column_fkey"
I've tried to explicitly:
我试图明确:
from sqlalchemy.exc import IntegrityError
UPDATE:
更新:
I found something that seems to fit what's happening here, where Integrity Error isn't thrown until the session is flushed to the db, and after the try
/except
blocks have been executed: Trying to catch integrity error with SQLAlchemy
我发现了一些似乎适合这里发生的事情的东西,在会话刷新到数据库之前不会抛出完整性错误,并且在try
/except
块被执行之后:尝试使用 SQLAlchemy 捕获完整性错误
However, adding session.flush()
in the try
block yields an InvalidRequestError
:
但是,session.flush()
在try
块中添加会产生一个InvalidRequestError
:
ERROR:root: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: (IntegrityError)
回答by Jason
As soon as the IntegrityError
is raised, regardless of whether or not you've caught the error, the session you were working in is invalidated. As the second error message is instructing you, To begin a new transaction with this Session, first issue Session.rollback().
, to continue using the session you'll need to issue a session.rollback()
一旦IntegrityError
引发,无论您是否发现错误,您正在使用的会话都将失效。由于第二条错误消息指示您To begin a new transaction with this Session, first issue Session.rollback().
继续使用会话,您需要发出session.rollback()
I cannot say for sure, but I am guessing you or your web framework is attempting to continue using the session which raised the IntegrityError in some way. I recommend you issue a session.rollback()
either after you catch the exception or in your handle_elegantly
function.
我不能肯定地说,但我猜您或您的 Web 框架正试图继续使用以某种方式引发 IntegrityError 的会话。我建议您session.rollback()
在捕获异常后或在您的handle_elegantly
函数中发出 a 。
If you run the below you'll see what I mean:
如果你运行下面的你会明白我的意思:
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")
回答by JsonBruce
I have the same need in my Flask application, I handle it like below and it works:
我在 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:
db.session.rollback()
回答by ivan
SQLALCHEMY_COMMIT_ON_TEARDOWN = False