2013-09-16 15 views
9

Mam następujący Mapping (prosto z przykładów SA):sqlalchemy session.refresh nie odświeżyć obiekt

class User(Base): 
    __tablename__ = 'users' 

    id = Column(Integer, primary_key=True) 
    name = Column(String) 
    fullname = Column(String) 
    password = Column(String) 

pracuję z MySQL DB i tabela ma silnik InnoDB.

Mam pojedynczy rekord w moim tabeli: 1 | 'user1' | 'test user1' | 'password'

Mam otworzył sesję z następującego kodu:

from sqlalchemy.orm.session import sessionmaker 
from sqlalchemy.engine import create_engine 
from sqlalchemy.orm.scoping import scoped_session 
from sqlalchemy.ext.declarative import declarative_base 

Base = declarative_base() 

db_engine = create_engine('mysql://[email protected]/test_db?charset=utf8',echo=False,pool_recycle=1800) 
session_factory = sessionmaker(bind=db_engine,autocommit=False,autoflush=False) 
session_maker = scoped_session(session_factory) 
session = session_maker() 

user_1 = session.query(User).filter(User.id==1).one() 
user_1.name # This prints: u'user1' 

teraz, kiedy zmienić nazwę rekordu w DB do „user1_change” i zobowiązać go, a następnie odśwież przedmiotu takiego:

session.refresh(user_1) 
user_1.name # This still prints: u'user1' and not u'user1_change' 

nadal drukuje: u'user1' i nie u'user1_change”.

Czego tu brakuje (lub źle się tu ustawia)?

Dzięki!

+0

Co to jest kod został użyty do popełnienia zmiany nazwy? Czy nazwa rzeczywiście zmieniła się w bazie danych? –

+0

Lub przez "kiedy zmieniam nazwę rekordu w DB", masz na myśli, że zmieniasz rekord używając innych środków niż sesja SQLAlchemy (np. Używając czegoś takiego jak phpMyAdmin)? –

+0

pracy z mysql-workbech, zmieniłem wartość w db i popełnione, całkowicie pod radarem SQLalchemy - ale to nie powinno mieć znaczenia, prawda? – wilfo

Odpowiedz

8

Z docs:

pamiętać, że bardzo odizolowane transakcja zwróci te same wartości jak wcześniej przeczytać w tej samej transakcji, niezależnie od zmian w stanie bazy poza tą transakcją

SQLAlchemy wykorzystuje transakcyjny model jednostki pracy, w którym zakłada się, że każda transakcja jest wewnętrznie spójna. Sesja to interfejs na szczycie transakcji. Ponieważ zakłada się, że transakcja jest wewnętrznie spójna, SQLAlchemy będzie tylko (dobrze, nie całkiem, ale dla łatwości wyjaśnienia ...) odzyskać dane z bazy danych i zaktualizować stan powiązanych obiektów raz na transakcję. Ponieważ już odpytałeś o obiekt w tej samej transakcji sesji, SQLAlchemy nie zaktualizuje danych w tym obiekcie z bazy danych ponownie w ramach tego zakresu transakcji. Jeśli chcesz odpytać bazę danych, musisz za każdym razem wykonać nową transakcję.

+0

Ma to sens, ale nie rozumiem, kiedy odświeżanie lub aktualizowanie spowoduje ponowne pobranie sesji z DB, to znaczy, co należy zrobić, aby odświeżyć i wygasić, przerwać transakcję, nie? – wilfo

+0

Obiekty dołączone do sesji nie muszą być ładowane z bazy danych. Mogłyby zostać skonstruowane lub zmodyfikowane lokalnie lub połączone z innej sesji. Zakres transakcyjny gwarantuje tylko, że dane będą * odczytane z bazy danych * raz na transakcję, a nie stan zmapowanego obiektu zmieni się tylko raz dla każdej transakcji. –

+0

Tak więc, aby upewnić się, że rozumiem, co tu mówisz - session.refresh i session.expire będą działać tylko w silnikach tabel, które nie wymuszają transakcji? Czy możesz opisać przypadek, w którym odświeżenie zadziała? – wilfo

0

Scal sesję.

u = session.query(User).get(id) 
u.name = 'user1_changed' 
u = session.merge(u) 

Spowoduje to aktualizację bazy danych i zwrócenie nowszego obiektu.

+0

Czy ta praca dla ciebie? Próbowałem również i nadal otrzymuję te same wartości. – wilfo

+1

Zgodnie z tym, jak czytają docs, to nie powinno działać. Musiałbyś scalić obiekt z nowo utworzoną sesją. –

+0

Przepraszam, zapomniałem o commit(). Zwykle używam menedżera kontekstu dla bloku transakcji. – umeboshi

2

session.refresh() też nie działa. Mimo że zobaczyłem WYBÓR niskiego poziomu, obiekt nie został zaktualizowany po odświeżeniu.

Ta odpowiedź https://stackoverflow.com/a/11121788/562267 wskazówki do prowadzenia rzeczywistej commit/rollback do zresetowania sesji, i że pracował dla mnie:

user_1 = session.query(User).filter(User.id==1).one() 
user_1.name # This prints: u'user1' 
# update the database from another client here 
session.commit() 
user_1 = session.query(User).filter(User.id==1).one() 
user_1.name # Should be updated now. 
Powiązane problemy