2013-09-16 69 views
9

我有以下的映射(直接從SA的例子):SQLAlchemy的session.refresh不會刷新對象

class User(Base): 
    __tablename__ = 'users' 

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

我與一個MySQL數據庫和工作表有一個InnoDB引擎。

我有我的表中的一條記錄: 1 | 'user1的' | 'user1的測試' | '密碼'

我已經打開用下面的代碼會話:

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' 

現在,當我在DB更改記錄的名稱爲「user1_change」並提交,然後刷新這樣的對象:

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

它仍然打印:u'user1' ,而不是u'user1_change」。

我在這裏錯過了什麼(或設置錯誤)?

謝謝!

+0

什麼是你用來提交名稱更改的代碼?數據庫中的名稱是否真的發生了變化? –

+0

或者「當我在數據庫中更改記錄名稱」時,您的意思是使用除SQLAlchemy會話之外的其他方式(例如,使用類似phpMyAdmin的內容)更改記錄? –

+0

與mysql-workbech一起工作,我改變了數據庫中的值並提交,完全在SQLalchemy的雷達下 - 但那應該不重要,對吧? – wilfo

回答

8

docs

注意,高度隔離交易將在數據庫狀態返回相同的值在同一事務以前讀,不管變化是事務之外

SQLAlchemy使用事務性工作單元模型,其中每個事務被假定爲內部一致的。會話是交易頂部的接口。由於事務被認爲是內部一致的,因此SQLAlchemy只會(不完全,但爲了便於解釋...)從數據庫中檢索給定數據並在每次事務中更新關聯對象的狀態。由於您已經在同一會話事務中查詢過該對象,SQLAlchemy將不會再次在該事務範圍內從數據庫更新該對象中的數據。如果您想輪詢數據庫,則需要每次都進行新的事務處理。

+0

這是有道理的,但我不明白什麼時候刷新或更新會使會話從數據庫中重新獲取,我的意思是,這就是刷新和過期所要做的事情,打破交易,不是? – wilfo

+0

附加到會話的對象不需要從數據庫加載。它們可能是在本地構建或修改的,也可能是從不同的會話合併而來。事務範圍只保證數據只能從數據庫中*讀取一次,而不是每個事務只能更改一次映射對象的狀態。 –

+0

所以爲了確保我明白你在這裏說的話 - session.refresh和session.expire只能在不執行事務的表引擎上工作? 你能描述一種刷新工作的情況嗎? – wilfo

0

合併會話。

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

這將更新數據庫,並返回更新的對象。

+0

這是否適合您?我已經嘗試過,並且仍然獲得相同的值。 – wilfo

+1

根據文檔的閱讀方式,這不應該起作用。您必須將對象合併到新創建的會話中。 –

+0

對不起,我忘了commit()。我通常使用事務塊的上下文管理器。 – umeboshi

2

session.refresh()也不適用於我。儘管我看到低級別的SELECT,刷新後對象並未更新。

這個答案https://stackoverflow.com/a/11121788/562267提示,做一個實際的提交/回滾重置會話,併爲我工作:

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.