We need to talk about the "I" in ACID (Neo4j corresponds to ACID), which means "isolation". The isolation level tells you how many other transactions are running at the same time as transactions.
The default isolation level in Neo4j is “read”. This means that A will not see that data B is written until B is committed. This is achieved using automatic locking, which works as follows:
Neo4j read-locks blocks nodes and relationships when you read them (you can get a lot of read locks), and also blocks nodes and links when they change. A read lock cannot be obtained with a write lock, and a write lock cannot be obtained with another write lock. Locks are released when a transaction is completed.
However, some anomalies can occur at this level of isolation, one of which is called a “lost update”.
To illustrate, let c be your counter value (I understand that an atom counter is what you end up with after that). Both transactions increment the counter by 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)
Update Tx1 done lost.
To avoid this, you need to change the isolation level to "repeat reading" by writing-locking objects that you are going to explicitly change before starting, before reading their current value. Thus, they will not be editable by any other concurrent transaction.
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)
Hope this makes it easier.
source share