2012-06-29 56 views
1
cities = DBSession.query(City).filter(City.big=='Y').options(joinedload(City.hash)).limit(1) 

t0 = time.time() 
keyword_statuses = DBSession.query(KeywordStatus).filter(KeywordStatus.status==0).options(joinedload(KeywordStatus.keyword)).with_lockmode("update").limit(1) 

for kw_status in keyword_statuses: 
    kw_status.status = 1 
    DBSession.commit() 

t0 = time.time() 
w = SWorker(threads_no=1, network_server='http://192.168.1.242:8180/', keywords=keyword_statuses, cities=cities, saver=MySqlRawSave(DBSession), loglevel='debug') 

w.work() 

print 'finished' 

上述代碼從表中選擇關鍵字狀態並進行更新。 它鎖定行直到行被更新。mysql和sqlalchemy with_lockmode('update')它是如何工作的?

正如您所看到的,我更新了行並提交了更改。

kw_status.status = 1 
DBSession.commit()  

之後,我創建了一個SWorker對象,放在一個隊列中的任務,並創建一個 數量的處理隊列(這裏只是一個爲簡單起見)線程。

當它完成處理的工作人員在這一點上更新

kw_status.status = 2 
DBSession.commit() 

我得到一個異常

(1205, 'Lock wait timeout exceeded; try restarting transaction') 'UPDATE g_search_keyword_status SET status=%s WHERE g_search_keyword_status.keyword_id = %s' (2, 10000001L) 

如此看來,該行被鎖定。但在我啓動工作人員之前,我已將 狀態更新爲1,並且我已提交更改,以便將行解鎖。

而且我用的是scoped_session

DBSession = scoped_session(
    sessionmaker(
    autoflush=True, 
    autocommit=False, 
    bind=engine 
    ) 
) 

回答

1

問題是延遲加載。通知

keyword_statuses = DBSession.query(KeywordStatus).filter(KeywordStatus.status==0).options(joinedload(KeywordStatus.keyword)).with_lockmode("update").limit(1) 

for kw_status in keyword_statuses: 
    kw_status.status = 1 
DBSession.commit() 

上面的代碼不會將結果加載到內存中,但只有當它實際需要時。

而在我的SWORKer中,我循環訪問keywordStatus.keyword對象,所以表鎖定了foreach線程。

當我使用所有()

keyword_statuses = DBSession.query(KeywordStatus).filter(KeywordStatus.status==0).options(joinedload(KeywordStatus.keyword)).with_lockmode("update").limit(1).all() 
加載的結果到存儲器解決的問題