Neo4j 合并和原子事务
Posted
技术标签:
【中文标题】Neo4j 合并和原子事务【英文标题】:Neo4j Merge and Atomic Transaction 【发布时间】:2015-12-16 00:49:51 【问题描述】:我在 10 个并行线程中从客户端应用程序对我的 Neo4j 服务器运行以下 MERGE
查询,newFoo
和 id
参数在所有 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());
【问题讨论】:
记录一下,newFoo
和id
参数其实是不一样的。 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 => LockClient[31] <-[:HELD_BY]- RWLock[NODE(980), hash=779731960] <-[:WAITING_FOR]- LockClient[25] <-[: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 个公共节点的节点
尝试在Neo4J C#Client上使用相同的命令进行展开和合并
android如何将SQLite 3.7 WAL文件的内容合并到主数据库文件中?
正在加载CSV Neo4j“ Neo.ClientError.Statement.SemanticError:无法使用Test1'的空属性值合并节点”