2012-06-15 54 views
2

我有這個運行在一個網站上。當用戶登錄時,我查詢他的個人資料以查看他有多少可用的「積分」。積分通過paypal購買。如果某人購買了信用額並且付款已經完成,那麼即使我在phpmyadmin中運行相同的查詢,該查詢仍會顯示0個信用額度,但會帶來正確的結果。如果我重新啓動apache web服務器並重新加載頁面,正在顯示正確的信用數量。這裏是我的映射器代碼,顯示信用的數量每個用戶:sqlalchemy緩存一些查詢

mapper(User, users_table, order_by = 'user.date_added DESC, user.id DESC', properties = { 
    'userCreditsCount': column_property( 
     select( 
      [func.ifnull(func.sum(orders_table.c.quantity), 0)], 
      orders_table.c.user_id == users_table.c.id 
     ).where(and_( 
      orders_table.c.date_added > get_order_expire_limit(), # order must not be older than a month 
      orders_table.c.status == STATUS_COMPLETED 
     )).\ 
     label('userCreditsCount'), 
     deferred = True 
    ) 
    # other properties.... 
}) 

我使用的是瓶中框架SQLAlchemy的,但沒有使用他們的燒瓶SQLAlchemy的包裝(只是純粹的SQLAlchemy)

下面是如何啓動我的數據庫:

engine = create_engine(config.DATABASE_URI, pool_recycle = True) 
metadata = MetaData() 
db_session = scoped_session(sessionmaker(bind = engine, autoflush = True, autocommit = False)) 

我學會了Python和SQLAlchemy的這個項目,所以我可能會丟失的東西,但是這一次我發瘋。有任何想法嗎?

回答

0

sessionmaker的自動提交爲真,並看看是否有幫助,根據文件sessionmaker緩存

身份地圖模式,並將對象鎖定到他們的主鍵。但是,它不會執行任何類型的查詢緩存。

所以在你的代碼將變爲:

sessionmaker(bind = engine, autoflush = True, autocommit = True) 
+0

我不認爲autocommit設置爲True是一個聰明的方法。他們甚至不會在他們的文檔中推薦它。 –

2

請嘗試訪問該領域userCreditsCount之前打電話給你的對象refresh or expire

user1 = session.query(User).get(1) 
# ... 
session.refresh(user1, ('userCreditsCount',)) 

這將使查詢再次執行(當刷新被調用時)。

但是,根據事務使用的隔離模式,它可能無法解決問題,在這種情況下,您可能需要提交/回滾事務(會話),以便查詢爲您提供新結果。

1

Lifespan of a Contextual Session

我會確保你在會議結束時,當你用它做。

session = db_session() 
try: 
    return session.query(User).get(5) 
finally: 
    session.close() 
3

當你與一個會議的工作,一旦它開始使用連接,它保存到該連接,直到提交(),回滾()或close()被調用。使用DBAPI,與數據庫的連接也將保留在事務中,直到事務被提交或回退。

在這種情況下,當您將數據加載到會話中時,SQLAlchemy不會刷新數據,直到事務結束(或者您使用expire()明確過期部分數據)。這是自然的行爲,因爲由於transaction isolation,很可能當前交易不能從看到自任何情況下開始該交易以來發生的變化。

因此,儘管使用expire()或refresh()可能會或可能不會成爲如何將最新數據導入會話的一部分,但實際上您需要結束事務並啓動一個新事務以真正查看其他地方發生了什麼變化自那筆交易開始以來。您應該組織您的應用程序,以便在發出新請求時準備好一個特定的Session(),但是當請求完成時,Session()應該被關閉,並且一個新的請求(或至少一個新的事務)在下一個請求中啓動。