Neo4j/Cypher 在高并发环境中创建唯一关系

Neo4j/Cypher create unique relationship in highly concurrent environment

我需要为给定的关系类型设置某种唯一约束。

(a)-[:RELATION]->(b)

为了实现这一点,我使用 CREATE UNIQUE (a)-[:RELATION]->(b)

在并发环境中,如果多个线程可以在相同节点之间创建 (a)-[:RELATION]->(b),我得到 UniquePathNotUniqueException 并且由于 neo4j 事务隔离的性质而创建多个关系。

我发现目前创建唯一关系的唯一方法是写入锁定两个节点。

是否有其他方法可以创建有保证的唯一关系?

更新

这就是我最后使用的方法

MATCH (a), (b) 
SET a._lock_ = true, b._lock_ = true 
MERGE (a)-[:RELATION]->(b) 
REMOVE a._lock_, b._lock_

使用带有指数退避过程的附加重试循环可能会出现死锁。

您需要在关系上使用 MERGE,但事先您需要获取锁以防止并发问题。这是最容易完成的,因为删除不存在的 属性:

会产生副作用
MATCH (a:Label{key:value}), (b:Label{key:value2})
REMOVE a._non_existing_property, b._non_existing_property
MERGE (a)-[:RELATION]->(b)

更新

我上面的陈述有死锁的危险(Neo4j 会检测到并优雅地处理)。为了防止必须以一致的顺序获取锁,例如按较小的节点 ID:

MATCH (a:Label{key:value}), (b:Label{key:value2})
WITH a, b, case when id(a) < id(b) then a else b end as locknode
REMOVE locknode._non_existing_property
MERGE (a)-[:RELATION]->(b)

这就是我最后使用的方法

MATCH (a), (b) 
SET a._lock_ = true, b._lock_ = true 
MERGE (a)-[:RELATION]->(b) 
REMOVE a._lock_, b._lock_

使用带有指数退避的附加重试循环来处理可能的死锁。