数据库异常后SQLAlchemy回滚中的错误?

Saq*_*Ali 9 python mysql sqlalchemy rollback flask-sqlalchemy

我的SQLAlchemy应用程序(在MariaDB之上运行)包括两个模型MyModelA,MyModelB后者是前者的子记录:

class MyModelA(db.Model):
    a_id   = db.Column(db.Integer, nullable=False, primary_key=True)
    my_field1 = db.Column(db.String(1024), nullable=True)

class MyModelB(db.Model):
    b_id   = db.Column(db.Integer, nullable=False, primary_key=True)
    a_id = db.Column(db.Integer, db.ForeignKey(MyModelA.a_id), nullable=False)
    my_field2 = db.Column(db.String(1024), nullable=True)
Run Code Online (Sandbox Code Playgroud)

这些的实例MyModelAMyModelB我创建:

>>> my_a = MyModelA(my_field1="A1")
>>> my_a.aid
1
>>> MyModelB(a_id=my_a.aid, my_field2="B1")
Run Code Online (Sandbox Code Playgroud)

我有以下代码删除MyModelAwhere 的实例a_id==1:

db.session.commit()
try:
    my_a = MyModelA.query.get(a_id=1)
    assert my_a is not None
    print "#1) Number of MyModelAs: %s\n" % MyModelA.query.count()
    db.session.delete(my_a)
    db.session.commit()
except IntegrityError:
    print "#2) Cannot delete instance of MyModelA because it has child record(s)!"
    db.session.rollback()
    print "#3) Number of MyModelAs: %s\n" % MyModelA.query.count()
Run Code Online (Sandbox Code Playgroud)

当我运行此代码时,请查看我得到的意外结果:

#1) Number of MyModelAs: 1
#2) Cannot delete instance of MyModelA because it has child record(s)!
#3) Number of MyModelAs: 0
Run Code Online (Sandbox Code Playgroud)

删除假定失败,数据库抛出异常导致回滚.但是,即使在回滚之后,表中的行数也表明该行 - 据说没有被删除 - 实际上已经消失了!

为什么会这样?我怎样才能解决这个问题?这似乎是SQLAlchemy中的一个错误.

Mik*_*ike 1

TL;DR 您的问题可能与缺乏明确的关系声明有关。

例如,这里有一个对象关系的示例。除了使用foreignkey字段之外,该类还显式使用指令relationship来定义该连接。在会话 API 文档中,出现以下文本:

对象引用应该在对象级别构建,而不是在外键级别构建

这可能暗示了 SQLAlchemy 管理关系的方式。我不太熟悉底层机制,但可能会发生这种情况。您的会话仅包含该MyModelA对象。由于您没有relationship()在 的定义中使用该指令MyModelBMyModelA因此类型的对象不知道某些其他对象可能通过 引用它们ForeignKey。因此,当会话即将提交时,它不会意识到删除该对象会影响其他MyModelB对象,并且其事务机制不会考虑到这一点。我建议明确添加关系可能会阻止这种行为。