Neo4j 合并和原子事务

Posted

技术标签:

【中文标题】Neo4j 合并和原子事务【英文标题】:Neo4j Merge and Atomic Transaction 【发布时间】:2015-12-16 00:49:51 【问题描述】:

我在 10 个并行线程中从客户端应用程序对我的 Neo4j 服务器运行以下 MERGE 查询,newFooid 参数在所有 10 次运行中都相同:

MERGE (foo:Foo  id: id )
ON MATCH
SET foo = newFoo

运行此程序后,我运行以下查询以期待 1 但我却得到 10

match (f:Foo)
return count(f)

我认为MERGE 在原子事务中运行,但显然不是。我在这里做错了吗?

更新

下面是我用来重现问题的代码:

public static async Task RunInParallel()

    var client = new GraphClient(new Uri("http://localhost:7474/db/data"), "neo4j", "1234567890")
    
        JsonContractResolver = new CamelCasePropertyNamesContractResolver()
    ;

    client.Connect();

    var foo = new Foo
    
        Id = "1",
        Name = "Foo",
        Slug = "foo-bar-foo"
    ;

    List<Task> tasks = new List<Task>();
    for (int i = 0; i < 10; i++)
    
        var task = client.Cypher
            .Merge("(foo:Foo  id: id )")
            .OnMatch()
            .Set("foo = newFoo")
            .WithParams(new
            
                Id = foo.Id,
                NewFoo = foo
            )
            .ExecuteWithoutResultsAsync();

        tasks.Add(task);
    

    await Task.WhenAll(tasks.ToArray());

【问题讨论】:

记录一下,newFooid参数其实是不一样的。 newFoo 值(在驼峰式解析之后)是 id: "1", name: "Foo", slug: "foo-bar-foo"id 参数值就是"1" 你的 id-property 也有不同的拼写,一次是大写的 I,一次是小写的 i 如果你只有 2 个额外的参数。 1.使用ON CREATE !!! 2.使用SET foo.name = newFoo.name, foo.slug = newfoo.slug @MichaelHunger 是的,但 mky 客户端设置上的 CamelCasePropertyNamesContractResolver 应该可以处理。 【参考方案1】:

MERGE(本身)不保证唯一性。使用MERGE(在唯一属性上)时,您应该始终为指定属性创建uniqueness constraint:

CREATE CONSTRAINT ON (f:Foo) ASSERT f.id IS UNIQUE

这将确保您不会创建任何重复项。

编辑

MERGE 没有唯一性约束不是线程安全的。添加唯一性约束可确保在写入之前持有索引锁,从而使操作线程安全。

【讨论】:

好吧,添加唯一约束会使情况变得更糟,出现死锁错误:"DeadlockDetectedException: LockClient[31] can't wait on resource RWLock[INDEX_ENTRY(49), hash=2045111578] since =&gt; LockClient[31] &lt;-[:HELD_BY]- RWLock[NODE(980), hash=779731960] &lt;-[:WAITING_FOR]- LockClient[25] &lt;-[:HELD_BY]- RWLock[INDEX_ENTRY(49), hash=2045111578]" @tugberk 添加唯一性约束可确保 Neo4j 在使用 MERGE 时获取锁 - 因此在高并发写入时会出现死锁异常。尝试捕获 DeadlockException 并实现重试循环。更多信息在这里:neo4j.com/docs/stable/transactions-deadlocks.html @DavidFox 感谢您的反馈。我会把它传下去。使用没有唯一性约束的 MERGE 不是线程安全的。添加唯一性约束通过使用索引锁确保 MERGE 的线程安全。 谢谢@WilliamLyon。在文档中对此进行一些反映肯定会很有用。我以前也遇到过类似的问题,对我来说,似乎可以以更好的方式记录 Neo4j 中的锁定概念。另外,我对锁定系统的细节不太熟悉,但对我来说,仅仅简单的 MERGE 查询就会陷入僵局似乎很奇怪,因为 MERGE 的全部意义在于创建或返回/更新一个已经存在的实体。 @WilliamLyon 这有点不幸,MERGE 这个词完全让我失望了。被称为MERGE 并具有其当前行为的事实是如此令人困惑。我希望MERGE 能够静默处理锁定,以原子方式创建资源并将节点引用交给我。否则,它与 CREATE 在具有唯一约束的节点上没有什么不同(如果我没记错的话)。

以上是关于Neo4j 合并和原子事务的主要内容,如果未能解决你的问题,请参考以下文章

Neo4j Cypher:查找/合并具有至少 2 个公共节点的节点

如何使用py2neo v4和Neo4j合并节点和关系

尝试在Neo4J C#Client上使用相同的命令进行展开和合并

android如何将SQLite 3.7 WAL文件的内容合并到主数据库文件中?

正在加载CSV Neo4j“ Neo.ClientError.Statement.SemanticError:无法使用Test1'的空属性值合并节点”

我可以在 Oracle 中进行原子合并吗?