2016-11-18 72 views
8

我SQLAlchemy的应用(上MariaDB的上运行)包括两种型号MyModelAMyModelB其中,后者是前者的子记录:数据库异常后SQLAlchemy回滚中的错误?

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) 

这些是我创造的MyModelAMyModelB实例:

>>> my_a = MyModelA(my_field1="A1") 
>>> my_a.aid 
1 
>>> MyModelB(a_id=my_a.aid, my_field2="B1") 

我有下面的代码删除的MyModelA的实例,其中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() 

当我运行这段代码看看意想不到的结果我得到:

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

的删除据说失败和DB抛出导致回滚异常。然而,即使在回滚之后,表中的行数也表明该行(据说未被删除)实际上已经消失了!

这是怎么发生的?我怎样才能解决这个问题?这看起来像SQLAlchemy中的一个错误。

+0

你检查autocommit是否被禁用? –

+0

同样的想法:你说你使用MariaDB。 MariaDB中的哪种引擎? MyISAM不支持事务,所以它始终处于“自动提交”模式 –

+0

sqlalchemy生成的查询是什么? “SELECTs”有“FOR UPDATE”吗? –

回答

0

TL; DR 您的问题可能与缺乏明确的关系声明有关。例如,here有一个对象关系的样本。除了使用ForeignKey字段外,该类还明确使用relationship指令来定义该连接。在session API documentation,显示以下文字:

对象引用应在对象级别来构建,而不是在国外关键水平

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