2012-04-09 14 views
13

Poszukuję pełnego przykładu użycia polecenia select for update w SQLAlchemy, ale nie znalazłem jednego googlowania. Muszę zablokować jeden wiersz i aktualizować kolumnę, poniższy kod nie działa (bloki na zawsze):SQLAlchemy - wybierz przykład aktualizacji

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") 

Czy muszę popełnić? Jak mogę to zrobić? O ile wiem, trzeba: rozpocząć transakcję wybrać ... dla aktualizacji aktualizacji popełnienia

+1

Chcę również podkreślić obiekt Query ma nową metodę to: http://docs.sqlalchemy.org/en/rel_0_9 /orm/query.html#sqlalchemy.orm.query.Query.with_for_update –

Odpowiedz

2

Tak, trzeba zrobić, aby popełnić, które można wykonać na Engine lub utwórz Transaction jawnie. Również modyfikatory są określone w metodzie values(...), a nie execute:

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

Ta odpowiedź pomija główny punkt zadanego pytania, którym jest przykład użycia "SELECT ... FOR UPDATE". Kod z tego można sprowadzić do proponowanej formy, ale potem nie używa już żądanego konstruktu. Oczywiście, jeśli @Mark nie planuje dodawać żadnej dodatkowej logiki pomiędzy pozyskiwaniem blokad i aktualizowaniem rekordów, taka redukcja jest idealnie do zrobienia. – RobertT

6

Późne odpowiedź, ale może ktoś znajdzie to użyteczne.

Po pierwsze, nie musisz zatwierdzać (przynajmniej nie pośrednich zapytań, o których zakładam, że pytasz). Twoje drugie zapytanie zawiesza się na czas nieokreślony, ponieważ skutecznie tworzysz dwa równoczesne połączenia z bazą danych. Pierwszym jest uzyskanie blokady wybranych rekordów, a następnie próba modyfikacji zablokowanych rekordów. Więc nie może działać poprawnie. (Przy okazji, w podanym przykładzie nie wywołujesz w ogóle pierwszego zapytania, więc zakładam, że w twoich prawdziwych testach zrobiłeś coś takiego, jak gdzieś). Tak aby realizacja punkt pracy powinien wyglądać bardziej jak:

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() 

oczywiście w takim prostym przypadku nie ma powodu, aby robić żadnych blokowanie ale myślę, że jest to tylko przykład i planujecie dodać jakieś dodatkowe logiki między tymi dwa połączenia.

7

Jeśli używasz ORM, spróbuj with_for_update funkcję:

 
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

Powinno być Foo.id == 1234. Odniesienia: http://docs.sqlalchemy.org/en/latest/orm/query.html#sqlalchemy.orm.query.Query.filter – Kapucko

+0

@Kapucko Dzięki; edytowane. –

+0

@MatthewMoisen, czy możesz mi powiedzieć, dlaczego używasz 'add'? jeśli go nie używam, czy będzie w porządku? –