Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python zodb:数据库冲突失败_Python_Database_Multithreading_Conflict_Zodb - Fatal编程技术网

Python zodb:数据库冲突失败

Python zodb:数据库冲突失败,python,database,multithreading,conflict,zodb,Python,Database,Multithreading,Conflict,Zodb,我有一个服务器和一个客户端 客户端发送一个请求。该请求具有与之关联的特定密钥,例如a-1、a-2、b-1、b-4 如果对同一密钥的两个请求同时出现,则会出现冲突错误,因为相同的数据结构正在被修改 我可以调整客户端,使其不同时发送同一密钥的两个请求。但是,我希望这个系统也能与多个客户机一起工作。让客户端协调发送给服务器的内容似乎很愚蠢。相反,如果某个密钥已经被修改,我希望服务器只是简单地阻止该密钥的请求,直到使用该密钥的其他请求完成 为此,我创建了一个锁定系统。在服务器上的函数开始时,我执行以下操

我有一个服务器和一个客户端

客户端发送一个请求。该请求具有与之关联的特定密钥,例如a-1、a-2、b-1、b-4

如果对同一密钥的两个请求同时出现,则会出现冲突错误,因为相同的数据结构正在被修改

我可以调整客户端,使其不同时发送同一密钥的两个请求。但是,我希望这个系统也能与多个客户机一起工作。让客户端协调发送给服务器的内容似乎很愚蠢。相反,如果某个密钥已经被修改,我希望服务器只是简单地阻止该密钥的请求,直到使用该密钥的其他请求完成

为此,我创建了一个锁定系统。在服务器上的函数开始时,我执行以下操作:

key = ...
print "Acquiring %s lock..." % (key,)
KEY_LOCKS[key].acquire()
print "%s lock acquired." % (key,)
def after_commit_hook(success):
    KEY_LOCKS[key].release()
    print "(after %s commit): Released %s lock" % (('failed', 'successful')[success], key)
transaction.get().addAfterCommitHook(after_commit_hook)
其中KEY_LOCKS是将KEY映射到threading.LOCKS的dict。之后是修改持久数据结构的代码

我假设会发生的情况是,如果一个请求进入一个已经被处理的密钥,它将在获取锁时阻塞。只有当先前的请求已经提交,因此没有任何冲突错误时,新请求才会恢复。在获取锁之前,请求不会执行任何可能发生冲突的操作

大多数请求都可以正常工作:

Acquiring a-b lock...
a-b lock acquired.
(after successful commit): Released a-b lock
Acquiring a-c lock...
a-c lock acquired.
(after successful commit): Released a-c lock
但是,当发送相同的密钥时,仍然存在一个问题,即使锁定似乎有效:

Acquiring q-q lock...
q-q lock acquired.
Acquiring q-q lock...
(after successful commit): Released q-q lock
q-q lock acquired.
(after failed commit): Released q-q lock
repoze.retry retrying, count = 1
Traceback (most recent call last):
...
ConflictError: database conflict error (oid 0x13009b, class persistent.list.PersistentList)
然后请求重试。请注意,q-q锁仅在成功提交后获得

有什么好处?为什么这个系统不能防止冲突错误?我的假设哪里不正确

编辑:嗯,如果在transaction.get.addaftercommithook之前,在我放置transaction.begin的钩子行之后,它工作。为了我的生命,我不知道为什么。在transaction.begin行之前,我的全部代码是:

post = request.params
if not post: return Response("No data!")

data = eval(post['data'])
time_parsed = time.time() 
my_app = request.context

这解决了我的问题,但我不会把它作为一个答案,因为我仍然想知道:如果我之前没有开始一个新的事务,为什么它会给出冲突错误?

ZODB从事务开始的那一刻起就提供具有一致视图的连接。这意味着,在新事务开始之前,一个线程不会看到其他线程在数据库中所做的更改!这是数据库的基本特性,称为

换句话说,如果希望应用程序线程不因使用锁定而发生冲突,则还需要在锁定可用时启动新事务

在我看来,锁定是您希望避免的性能瓶颈。持有锁的时间越长,与数据库状态相比,您遇到不一致数据的可能性就越大


在Zope中,使用了乐观的方法:当引发冲突错误时,事务将中止,并从一开始重新重试。如果您的事务很短、很快,那么您可以避免大多数锁定问题,相反,只要持久性更改发生更改导致冲突,您就可以重新计算对数据库的更改。

考虑将其发布到ZODB-dev邮件列表。如果你得到答案,把它贴回这里。啊,这很有道理。谢谢你的解释!回复:锁定,可能确实没有必要。我会看看没有它我能做什么。