2012-04-09 1 views
13

Ich bin auf der Suche nach einem vollständigen Beispiel für die Verwendung von Select für die Aktualisierung in SQLAlchemy, aber nicht ein googeln gefunden. Ich brauche eine einzelne Zeile zu sperren und eine Spalte zu aktualisieren, der folgende Code funktioniert nicht (Blöcke für immer):SQLAlchemy - Wählen Sie für Update-Beispiel

s = table.select(table.c.user=="test",for_update=True) 
# Do update or not depending on the row 
u = table.update().where(table.c.user=="test")   
u.execute(email="foo") 

Muss ich begehen? Wie mache ich das? Soweit ich weiß, Sie brauchen: Transaktion beginnen wählen ... for update Update

+1

Möchten Sie auch das Query-Objekt, darauf hinzuweisen, ein neues Verfahren für diese hat: http://docs.sqlalchemy.org/en/rel_0_9 /orm/query.html#sqlalchemy.orm.query.Query.with_for_update –

Antwort

2

begehen Ja, Sie verpflichten müssen, die Sie auf dem Engine oder erstellen Sie eine Transaction explizit ausführen kann. Auch sind die Modifikatoren in der values(...) Methode angegeben, und nicht execute:

>>> conn.execute(users.update(). 
...    where(table.c.user=="test"). 
...    values(email="foo") 
...    ) 
>>> my_engine.commit() 
+2

Diese Antwort verfehlt den Hauptpunkt der gestellten Frage, nämlich das Anwendungsbeispiel SELECT ... FOR UPDATE. Code daraus kann auf die vorgeschlagene Form reduziert werden, aber dann verwendet er kein angefordertes Konstrukt mehr. Natürlich, wenn @Mark nicht geplant hat, zusätzliche Logik zwischen dem Erhalten von Sperr- und Aktualisierungsdatensätzen hinzuzufügen, ist eine solche Reduktion vollkommen in Ordnung. – RobertT

6

Späte Antwort, aber vielleicht jemand findet es nützlich.

Zunächst müssen Sie keine Festschreibung durchführen (zumindest keine Zwischenabfragen, von denen ich annehme, dass Sie danach fragen). Ihre zweite Abfrage hängt unbegrenzt, da Sie zwei gleichzeitige Verbindungen zur Datenbank erstellen. Zuerst wird die Sperre für ausgewählte Datensätze aktiviert, dann wird versucht, gesperrte Datensätze zu ändern. Es kann also nicht richtig funktionieren. (Übrigens rufen Sie im Beispiel nicht die erste Abfrage auf, also nehme ich an, dass Sie in Ihren echten Tests etwas wie s.execute() irgendwo gemacht haben). Also der Punkt-Arbeits Umsetzung aussehen sollte mehr:

s = conn.execute(table.select(table.c.user=="test", for_update=True)) 
u = conn.execute(table.update().where(table.c.user=="test), {"email": "foo"}) 
conn.commit() 

Natürlich in einem solchen einfachen Fall gibt es keinen Grund jede Verriegelung zu tun, aber ich denke, es ist nur als Beispiel und Sie planten einige zusätzliche Logik zwischen denen hinzufügen zwei Anrufe.

7

Wenn Sie die ORM verwenden, versuchen die with_for_update Funktion:

 
foo = session.query(Foo).filter(Foo.id==1234).with_for_update().one() 
# this row is now locked 

foo.name = 'bar' 
session.add(foo) 

session.commit() 
# this row is now unlocked 
+0

Es sollte Foo.id == 1234 sein. Referenz: http://docs.sqlalchemy.org/en/latest/orm/query.html#sqlalchemy.orm.query.Query.filter – Kapucko

+0

@Kapucko Thanks; bearbeitet. –

+0

@MatthewMoisen können Sie mir sagen, warum 'add' verwenden? wenn ich es nicht benutze, wird es in Ordnung sein? –