python - Google App Engine : How to do queries interact when they execute a function decorated by ndb. 事务

标签 python google-app-engine transactions google-cloud-datastore app-engine-ndb

为了了解ndb.transaction的内部工作原理,我尝试了以下实验。

Udacity 示例中的 session API 用于创建一个只有一个席位的 session 。

我在处理 registerForConference API 的方法中添加了等待,如下所示。我记录调试消息以了解流程,如下所示

我相继开始两次调用 registerForConference API。

如果没有ndb.transaction,两者都会返回true(即都返回注册成功)。对于 ndb.transaction,第二个将返回 false。所以,事情正在按预期进行。

但是第二个请求所经历的步骤顺序是出乎意料的。我预计第二个查询会在某个时刻卡住,直到第一个查询完成,并且在尝试插入时会抛出 TransactionFailedError 。相反,看起来第二个请求实际上通过了该方法一次,然后在第一个请求完成后重新执行该方法。在第二个异常中,它读取席位可用的更新值并确定它无法注册。这是预期的行为吗?如果是,这不是浪费吗,因为某些步骤可以并行完成,并且只有在第一个查询完成后才需要执行有冲突的步骤?

打印的调试日志消息序列

/_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)

最佳答案

这是预期的。它并不总是处理交易的最有效方法,但这是他们选择使用的模型 - 它假设事务冲突很少发生,并且只是在写入之前验证这一点。这称为“乐观并发”。另一种选择是锁定事物,这可能非常复杂,并且当事务不经常发生冲突时效率较低。

how transactions work on appengine 的文档可能有助于解释更多信息,或者 optimistic concurrency control 上有一个维基百科页面

关于python - Google App Engine : How to do queries interact when they execute a function decorated by ndb. 事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31767924/

相关文章:

python - 匹配和求和来自 2 个具有不相等行的数据帧的列

python - 无法提取文本并找到所有由 BeautifulSoup 提供的内容

python - 如何使用冗长的 Python 打印函数的开始和结束?

google-app-engine - Go Bigquery 上的 DEADLINE_EXCEEDED

python - Google App Engine 中 imp.load_module() 的替换功能?

mysql - spring transaction 是否仅在进入服务方法中起作用?

python - Boost python typedef

python - 使用 bulkloader 从 Google App Engine 下载数据时出错

javascript - 如何在 Loopback 中实现 ACID 事务

database - Laravel DB::rollback() 不适用于交易流程