我能以某种方式解决 ResourceIterator 惰性的这一特定方面吗?
Can I somehow work around this particular aspect of ResourceIterator's laziness?
当有两个并发事务 t1
和 t2
时(我将跳过样板文件,假设我正在按照书做所有事情):
线程 A:t1
:
it1 = db.findNodes(label);
it1.forEach(node -> println(node.hasLabel(label))
线程 B:t2
:
it2 = db.findNodes(label);
it2.forEach(node -> node.removeLabel(label))
现在,从我的角度来看,我们这里有一个 巨大的 不一致:如果线程 A 的执行速度比线程 B 慢,此时我们检查 A 中的节点是否有一个标签 label
,结果将是 false
!
作为一名开发人员,我知道由于迭代器是惰性的,所以这是可以预见的,我明白了这种行为背后的原因,但作为一名 API 用户,我真的很生气,因为我不能 100% 确定我请求的节点有 label
,结果没有!
此外,可能存在这样一种情况,即无法在任何实体上获得写锁以保护所有这些节点免受并发修改,因此即使使用一些优秀的工具我也无法保持一致性。
我真的不认为这是一个错误 - 而是一个疯狂的功能。但是,我真的很高兴知道是否有任何解决方案可以帮助我解决我的问题。
更新:这是这种伪竞争条件是如何发生的:
Before: create 100 nodes with :Label
A: get iterator for all nodes with :Label
B: get iterator for all nodes with :Label
A: consume e.g. 50 nodes
B: remove labels from all nodes, commit
A: see the rest of the nodes as the ones not having :Label
你的问题很棘手 - 由于没有人尝试回答,我会尝试一个。
我认为答案包含在 neo4j 如何处理事务的细节中。 This particular link dealing with transaction isolation 似乎与我很相关,它说:
Transactions in Neo4j use a read-committed isolation level, which
means they will see data as soon as it has been committed and will not
see data in other transactions that have not yet been committed. This
type of isolation is weaker than serialization but offers significant
performance advantages whilst being sufficient for the overwhelming
majority of cases.
我想当然地认为您删除这些标签是在交易中发生的。我读到的是,在所有线程 B 完成之前,线程 A 中的任何一个标签都不能更改。这是因为您可能会从许多节点中删除标签,但是在提交删除事务之前,其中的 none 是 real/visible 到任何其他线程。至少应该是这样。
所以这里的竞争条件是当线程 A 启动时 而 线程 B 正在执行,但 在 线程 B 提交之前。
我认为您的最佳答案可能来自 link 的第二段:
In addition, the Neo4j Java API (see Advanced Usage) enables explicit
locking of nodes and relationships. Using locks gives the opportunity
to simulate the effects of higher levels of isolation by obtaining and
releasing locks explicitly. For example, if a write lock is taken on a
common node or relationship, then all transactions will serialize on
that lock — giving the effect of a serialization isolation level.
在线程 B 内部,您可能希望 acquire a read lock 在您正在修改的节点上。该锁将在事务提交时释放。
我不是 100% 确定这个答案,但我认为它有道理。如果更有经验的人可以对此进行改进或反驳,请加入。
当有两个并发事务 t1
和 t2
时(我将跳过样板文件,假设我正在按照书做所有事情):
线程 A:t1
:
it1 = db.findNodes(label);
it1.forEach(node -> println(node.hasLabel(label))
线程 B:t2
:
it2 = db.findNodes(label);
it2.forEach(node -> node.removeLabel(label))
现在,从我的角度来看,我们这里有一个 巨大的 不一致:如果线程 A 的执行速度比线程 B 慢,此时我们检查 A 中的节点是否有一个标签 label
,结果将是 false
!
作为一名开发人员,我知道由于迭代器是惰性的,所以这是可以预见的,我明白了这种行为背后的原因,但作为一名 API 用户,我真的很生气,因为我不能 100% 确定我请求的节点有 label
,结果没有!
此外,可能存在这样一种情况,即无法在任何实体上获得写锁以保护所有这些节点免受并发修改,因此即使使用一些优秀的工具我也无法保持一致性。
我真的不认为这是一个错误 - 而是一个疯狂的功能。但是,我真的很高兴知道是否有任何解决方案可以帮助我解决我的问题。
更新:这是这种伪竞争条件是如何发生的:
Before: create 100 nodes with :Label
A: get iterator for all nodes with :Label
B: get iterator for all nodes with :Label
A: consume e.g. 50 nodes
B: remove labels from all nodes, commit
A: see the rest of the nodes as the ones not having :Label
你的问题很棘手 - 由于没有人尝试回答,我会尝试一个。
我认为答案包含在 neo4j 如何处理事务的细节中。 This particular link dealing with transaction isolation 似乎与我很相关,它说:
Transactions in Neo4j use a read-committed isolation level, which means they will see data as soon as it has been committed and will not see data in other transactions that have not yet been committed. This type of isolation is weaker than serialization but offers significant performance advantages whilst being sufficient for the overwhelming majority of cases.
我想当然地认为您删除这些标签是在交易中发生的。我读到的是,在所有线程 B 完成之前,线程 A 中的任何一个标签都不能更改。这是因为您可能会从许多节点中删除标签,但是在提交删除事务之前,其中的 none 是 real/visible 到任何其他线程。至少应该是这样。
所以这里的竞争条件是当线程 A 启动时 而 线程 B 正在执行,但 在 线程 B 提交之前。
我认为您的最佳答案可能来自 link 的第二段:
In addition, the Neo4j Java API (see Advanced Usage) enables explicit locking of nodes and relationships. Using locks gives the opportunity to simulate the effects of higher levels of isolation by obtaining and releasing locks explicitly. For example, if a write lock is taken on a common node or relationship, then all transactions will serialize on that lock — giving the effect of a serialization isolation level.
在线程 B 内部,您可能希望 acquire a read lock 在您正在修改的节点上。该锁将在事务提交时释放。
我不是 100% 确定这个答案,但我认为它有道理。如果更有经验的人可以对此进行改进或反驳,请加入。