python - 同时修改ZODB中的不同键

标签 python transactions zodb

我使用 ZODB 作为将通过 Web 服务修改的对象的持久存储。 下面是我简化问题的示例。 增量函数是从多个线程调用的。 我的问题是,当从两个线程同时调用不同键的增量时,我收到冲突错误。

我想应该可以解决这个问题,至少只要以正确的方式修改不同的键? 如果是这样,我没有找到关于如何...的示例(zodb 文档似乎有点分布在不同的站点上:/)

很高兴有任何想法......

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 :-('

最佳答案

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

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

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

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 数据进行计算(在发生冲突错误后) ,将在需要时自动读取新数据),然后尝试提交。如果提交成功,您就完成了:

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

关于python - 同时修改ZODB中的不同键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18098979/

相关文章:

python - 了解 concurrent.futures.Executor.map()

c# - TransactionScope 的层次结构

java - JPA插入事务并发

.net - 在单线程上使用事务时 sqlite 和 SubSonic 的锁定问题

plone - 将 my.packages 重命名为 my.package

python - 工作副本 checkin 时出现运行时错误(超出最大递归深度)

python - 在随机端口上绑定(bind) Tornado Web 服务器

python - 在Python中,我们如何将某个变量的先前值存储在另一个变量中?

python - 在 OpenCV 中检测二进制 blob

python - 在 Plone 中循环遍历损坏的对象