我们需要谈论ACID中的"I"(Neo4j符合ACID标准),其中"I"代表"隔离性"。隔离级别告诉您,同时运行的事务中有多少数据是互相可见的。
Neo4j的默认隔离级别是"读已提交"。这意味着A直到B提交后才能看到B写入的数据。这是通过自动锁定实现的,其工作方式如下:
当您读取节点和关系时(您可以获取许多读锁),Neo4j会对它们进行读取锁定,并在修改它们时对节点和关系进行写入锁定。当存在写入锁定时,无法获得读锁定;当存在另一个写入锁定时,无法获得写入锁定。锁将在事务提交时释放。
然而,在此隔离级别下可能会发生一些异常情况,其中之一称为"丢失更新"。
为了说明问题,假设c是您的计数器值(我理解您最终想要的是原子计数器)。两个事务都将计数器加1。
c=0
Tx1 reads c=0 (read locks c)
Tx2 reads c=0 (read locks c)
Tx1 writes c=1 (write locks c)
Tx1 commits (unlocks c)
Tx2 writes c=1 (because it thinks c is still 0, write locks c)
Tx2 commits (unlocks c)
更新Tx1所做的更改已经丢失。
为了防止这种情况发生,您需要将隔离级别更改为“可重复读”,通过显式地事先写锁定要修改的对象,然后再读取它们的当前值。这样,它们就不会被任何其他同时运行的事务修改。
c=0
Tx1 write locks c
Tx1 reads c=0
Tx2 tries to write lock c, has to wait
Tx1 writes c=1
Tx1 commits (unlocks c)
Tx2 write locks c (because it now can)
Tx2 reads c=1
Tx2 writes c=2
Tx2 commits (unlocks c)
希望这样可以让事情更清楚明白。
call apoc.lock.nodes([nodes])
。了解更多信息,请访问 neo4j-contrib.github.io/neo4j-apoc-procedures/#_locking。 - John