I have a project in nodejs and there are some concurrency issues. I have a handler that reads and then writes the updated state to my neo4j database for the same node. When 2 concurrent processes try to run the same handler, the processes read from db the state and then one process writes the updated state above the other. So I want to lock before the read and unlock after the write.
Does neo4j has something ready for this? I found this and tried it to both reads and writes queries:
// read
MATCH (n:Account {id: $accountId})
CALL apoc.lock.nodes([n]) // Attempt to lock the account node
RETURN account.balance
// write
MATCH (n:Account {id: $accountId})
CALL apoc.lock.nodes([n]) // Lock the account node
SET n.balance = n.balance + $amount
RETURN account
// locks are released here??
but with no result and there is no enough documentation to know how to use it.
Any query example would be great! Thank you in advance!
I have a project in nodejs and there are some concurrency issues. I have a handler that reads and then writes the updated state to my neo4j database for the same node. When 2 concurrent processes try to run the same handler, the processes read from db the state and then one process writes the updated state above the other. So I want to lock before the read and unlock after the write.
Does neo4j has something ready for this? I found this and tried it to both reads and writes queries:
// read
MATCH (n:Account {id: $accountId})
CALL apoc.lock.nodes([n]) // Attempt to lock the account node
RETURN account.balance
// write
MATCH (n:Account {id: $accountId})
CALL apoc.lock.nodes([n]) // Lock the account node
SET n.balance = n.balance + $amount
RETURN account
// locks are released here??
but with no result and there is no enough documentation to know how to use it.
Any query example would be great! Thank you in advance!
Share Improve this question edited Nov 20, 2024 at 14:56 elli asked Nov 20, 2024 at 12:44 ellielli 6691 gold badge5 silver badges14 bronze badges 1- Show the implementation of your "handler". – cybersam Commented Nov 20, 2024 at 17:08
1 Answer
Reset to default 0For efficiency, neo4j uses the read-committed
isolation level by default, which does not put a lock on everything that is read from the DB by a transaction. However, data that a transaction writes is automatically locked from that point in the transaction. See here for more details.
The apoc.lock.nodes
procedure places a write-lock on each of the nodes in the provided list, but those locks are released at the end of the transaction that called the procedure. So, your "handler" must execute your read
and write
queries in the same transaction to prevent concurrent executions from stepping on each other. See the documentation for the neo4j driver for your programming language to see how to process queries in the same transaction.
Also, your write
query does not need to call apoc.lock.nodes
, since the immediately-following SET
clause would lock the n
node anyway (if the transaction had not locked it earlier). See the description and examples of "direct dependencies" in the docs.