唯一节点

这描述了如何在创建节点时确保属性的唯一性。

创建唯一节点

在许多用例中,实体之间需要一定程度的唯一性。例如,系统中可能只存在一个具有特定电子邮件地址的用户。如果多个并发线程天真地尝试创建用户,则会创建重复项。

以下是确保唯一性的主要策略,它们都适用于集群和单实例部署。

单线程

通过使用单线程,没有两个线程会同时尝试创建特定实体。在集群中,外部单线程客户端可以执行操作。

获取或创建

定义唯一性约束并使用 Cypher 的 MERGE 子句是获取或创建唯一节点的最有效方法。

示例的源代码可以在以下位置找到: GetOrCreateDocIT.java

创建唯一性约束

try ( Transaction tx = graphdb.beginTx() )
{
    tx.schema()
        .constraintFor( Label.label( "User" ) )
        .assertPropertyIsUnique( "name" )
        .withName( "usernames" )
        .create();
    tx.commit();
}

使用 MERGE 创建唯一节点

Node result = null;
ResourceIterator<Node> resultIterator = null;
try ( Transaction tx = graphDb.beginTx() )
{
    String queryString = "MERGE (n:User {name: $name}) RETURN n";
    Map<String, Object> parameters = new HashMap<>();
    parameters.put( "name", username );
    resultIterator = tx.execute( queryString, parameters ).columnAs( "n" );
    result = resultIterator.next();
    tx.commit();
    return result;
}

MERGE 子句要么对已存在的匹配节点进行读锁,要么进行写锁,并确保当前事务是唯一创建该节点的事务。

从技术上讲,可以使用锁定节点锁定属性,但应尽可能避免。使用锁定节点模式很难正确执行,并且性能特征更差,因为它始终涉及写锁。

您可能还会倾向于使用 Java 同步进行悲观锁定,但这很危险。通过混合 Neo4j 和 Java 运行时中的锁,可能会产生 Neo4j 检测不到的死锁。只要所有锁定都由 Neo4j 完成,所有死锁都将被检测到并避免。

有关锁和死锁的更多信息,请参见 操作手册→锁和死锁