2016-11-18 5 views
8

Meine SQLAlchemy Anwendung (oben auf MariaDB ausgeführt wird) umfasst zwei Modelle MyModelA und MyModelB wobei letztere ein Kinder des früheren ist:Fehler in SQLAlchemy Rollback nach DB-Ausnahme?

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) 

Das sind die Fälle von MyModelA und MyModelB sind, die ich schaffen:

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

ich habe den folgenden Code, der die Instanz von MyModelA löscht wo 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() 

Wenn ich diesen Code ausführen Blick auf die unerwarteten Ergebnisse, die ich erhalten:

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

Der löschen versagt angeblich und die DB löst eine Ausnahme, die ein Rollback verursacht. Aber auch nach dem Rollback gibt die Anzahl der Zeilen in der Tabelle an, dass die Zeile - die angeblich nicht gelöscht wurde - tatsächlich weg ist !!!

Warum passiert das? Wie kann ich das beheben? Es scheint wie ein Fehler in SQLAlchemy.

+0

Haben Sie überprüft, ob Autocommit deaktiviert ist? –

+0

gleiche Idee: Sie sagen, dass Sie MariaDB verwenden. Welche Art von Engine in MariaDB? MyISAM unterstützt keine Transaktionen, daher befindet es sich immer im "Autocommit" -Modus –

+0

Welche Abfragen werden von sqlalchemy generiert? Haben die 'SELECTs'' FOR UPDATE'? –

Antwort

0

TL; DR Ihr Problem könnte mit dem Fehlen einer expliziten Beziehungserklärung zusammenhängen.

Zum Beispiel here gibt es ein Beispiel für die Beziehung zwischen Objekten. Zusätzlich zur Verwendung eines ForeignKey-Felds verwendet die Klasse explizit die relationship-Direktive, um diese Verbindung zu definieren. Im session API documentation, wird der folgende Text:

Objektreferenzen sollten auf Objektebene konstruiert werden, nicht auf Fremdschlüssel Ebene

die auf dem Weg von SQLAlchemy bedeuten könnte die Beziehungen zu verwalten. Ich bin mit den zugrunde liegenden Mechanismen nicht sehr vertraut, aber es ist möglich, dass dies passiert. Ihre Sitzung enthält nur das Objekt MyModelA. Da Sie die relationship() Direktive in der Definition von MyModelB nicht verwendet haben, sind Objekte von MyModelA Typ nicht bewusst, dass ein anderes Objekt sie möglicherweise über eine ForeignKey verweist. Wenn die Sitzung kurz vor dem Festschreiben steht, ist sie daher nicht der Tatsache bewusst, dass das Löschen des Objekts sich auf ein anderes Objekt auswirkt, und sein Transaktionsmechanismus berücksichtigt dies nicht. Ich schlage vor, dass das Hinzufügen der Beziehung dieses Verhalten möglicherweise verhindert.