簡體   English   中英

Google App Engine:查詢執行由ndb.transaction裝飾的函數時如何交互

[英]Google App Engine: How to do queries interact when they execute a function decorated by ndb.transaction

為了了解ndb.transaction的內部工作原理,我嘗試了以下實驗。

Udacity中的Conference API示例用於創建只有一個席位的會議。

我在處理registerForConference API的方法中添加了一個等待,如下所示。 我將日志記錄調試消息理解為如下所示的流程

我一個接一個地開始了兩次調用registerForConference API。

如果沒有ndb.transaction,則兩者都將返回true(即,兩者都將成功注冊)。 使用ndb.transaction,第二個將返回false。 因此,一切按預期進行。

但是第二個請求執行的步驟順序是意外的。 我期望第二個查詢會在某個時候卡住,直到第一個查詢完成,並且在嘗試插入時將引發TransactionFailedError 相反,看起來第二個請求實際上一次通過了該方法,然后在第一個請求完成后重新執行該方法。 在第二個異常中,它讀取seatAvailable的更新值,並確定它無法注冊。 這是預期的行為嗎? 如果是的話,這是否不浪費資源,因為某些步驟可以並行執行,並且在第一次查詢完成后僅需要執行有沖突的步驟?

打印調試日志消息的順序

/_ah/spi/ConferenceApi.regForAConf
D 18:28:21.093 Checking for id_token.
D 18:28:21.093 id_token verification failed: Token is not an id_token (Wrong number of segments)
D 18:28:21.093 Checking for oauth token.
D 18:28:21.101 Returning user from matched oauth_user.
D 18:28:21.111 Entered conf registration check
D 18:28:21.125 Got a profile object
D 18:28:21.131 Got a conf object
D 18:28:21.131 Entered updating step
**Went through the entire method once**
**Then restarted after first API completed**
D 18:28:46.143 Leaving with exit value 1
D 18:28:46.168 Entered conf registration check
D 18:28:46.181 Got a profile object
D 18:28:46.187 Got a conf object
D 18:28:46.187 Transaction failed No seats available
D 18:28:46.187 Leaving with exit value 0

定義處理API請求的方法

   @ndb.transactional(xg=True) 
def _conferenceRegistration(self,confId):
    #get conference from id
    ret_val =True
    user = endpoints.get_current_user()
    if not user:
        raise endpoints.UnauthorizedException('Authorization required')
    user_id = getUserId(user)
    logging.debug('Entered conf registration check')
    p_key = ndb.Key(Profile, user_id)
    prof = p_key.get()

    logging.debug('Got a profile object')
    conf_key = ndb.Key(urlsafe=confId)
    conf = conf_key.get()
    logging.debug('Got a conf object')

    if conf and prof:
        if conf.seatsAvailable>0:
            logging.debug('Entered updating step')
            conf.seatsAvailable=conf.seatsAvailable-1
            time.sleep(25)
            prof.conferencesToAttend.append(conf.name)
            try:
                conf.put() 
            except TransactionFailedError:
                logging.debug('Transaction Failed error when trying to insert changes to conference')
                ret_val=False

            try:
                prof.put() 
            except TransactionFailedError:
                logging.debug('Transaction Failed error when trying to insert changes to profile')
                ret_val=False

            ret_val=True
        else:
            logging.debug('Transaction failed No seats available')
            ret_val=False  
    else:
        logging.debug('Could not get conf or profile instance')
        ret_val=False

    buf =  'Leaving with exit value %d' % (ret_val)   
    logging.debug(buf)
    return BooleanMessage(regSucc=ret_val)

這是預期的。 它並非始終是處理事務的最有效方法,但它是他們選擇使用的模型-它假定事務沖突很少發生,並且僅在編寫之前進行驗證。 這稱為“樂觀並發”。 另一種可能是涉及鎖定事物,這很復雜,並且在事務不經常發生沖突時效率較低。

有關在 Appengine上進行交易的工作方式的文檔可能會有助於解釋更多信息,或者在樂觀並發控制方面有wikkipedia頁面

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM