首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >同时修改ZODB中的不同键

同时修改ZODB中的不同键
EN

Stack Overflow用户
提问于 2013-08-07 08:57:07
回答 1查看 188关注 0票数 2

我使用ZODB作为要通过are服务修改的对象的持久存储。下面是我把这个问题减少到的一个例子。增量函数是从多个线程中调用的函数。我的问题是,当从两个线程同时调用增量时,对于不同的键,我将得到冲突错误。

我认为这应该是有可能解决这个问题,至少只要不同的键被修改,以适当的方式?如果是这样的话,我没能找到一个关于如何.(zodb文档似乎有些分散在不同的站点上:/ )

很高兴有任何想法..。

代码语言:javascript
复制
import time
import transaction
from ZODB.FileStorage import FileStorage
from ZODB.DB import DB
from ZODB.POSException import ConflictError

def test_db():
    store = FileStorage('zodb_storage.fs')
    return DB(store)

db_test = test_db()     

# app here is a flask-app
@app.route('/increment/<string:key>')
def increment(key):
    '''increment the value of a certain key'''

    # open connection
    conn = db_test.open()
    # get the current value:
    root = conn.root()
    val = root.get(key,0)    

    # calculate new value 
    # in the real application this might take some seconds
    time.sleep(0.1)
    root[key] = val + 1     

    try:
        transaction.commit()
        return '%s = %g' % (key, val)
    except ConflictError:
        transaction.abort()
        return 'ConflictError :-('
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-08-07 10:18:30

这里有两个选项:实现冲突解决,或者用新数据重试提交。

冲突解决只适用于您存储在ZODB中的自定义类型,并且只有当您知道如何将更改合并到新更改的状态时,才能应用。

ZODB查找自定义类型上的_p_resolveConflict()方法,并使用旧状态调用该方法、与之冲突的保存状态以及试图提交的新状态;您应该返回合并状态。对于一个简单的计数器(如您的示例中的例子),这将与使用新旧状态之间的更改更新保存的状态一样简单:

代码语言:javascript
复制
class Counter(Persistent):
    def __init__(self, start=0):
        self._count = start

    def increment(self):
        self._count += 1
        return self._count

    def _p_resolveConflict(self, old, saved, new):
        # default __getstate__ returns a dictionary of instance attributes
        saved['_count'] += new['_count'] - old['_count']
        return saved

另一种选择是重试提交;您希望限制重试的次数,并且您可能希望将其封装在方法的修饰器中,但基本原则是循环到极限,根据ZODB数据进行计算(在发生冲突后,这些数据将在需要时自动读取新的数据),然后尝试提交。如果提交成功,则完成:

代码语言:javascript
复制
max_retries = 10
retry = 0

conn = db_test.open()
root = conn.root()

while retry < max_retries:
    val = root.get(key,0)    
    time.sleep(0.1)
    root[key] = val + 1

    try:
        transaction.commit()
        return '%s = %g' % (key, val)
    except ConflictError:
        retry += 1

raise CustomExceptionIndicatingTooManyRetries
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18098979

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档