1

I'm starting to work with Neo4j and I noticed a really bad behaviour when updating a property on a node I am reading at the same moment. The clojure code I wrote use Neocons library to communicate with Neo4j:

(ns ams.utils.t.test-cypher-error
  (:require [clojurewerkz.neocons.rest :as rest]
            [clojurewerkz.neocons.rest.nodes :as nodes]
            [clojurewerkz.neocons.rest.cypher :as cypher]))

(rest/connect! "http://192.168.0.101:7474/db/data")

(def counter-id (:id (nodes/create {:counter 0})))

(defn update-counter [] (cypher/query "START c = node({id}) SET c.counter = c.counter + 1 RETURN c.counter as counter" {"id" counter-id}))

(doall (apply pcalls (repeat 10 update-counter)))

(println "Counter:" ((comp :counter :data) (nodes/get counter-id)))

(nodes/destroy counter-id)

Guess the result:

Counter: 4

Sometimes is 5, sometimes 4, but you got the problem here: between the START and the SET clause the value of the counter is changed but cypher doesn't catch it!

Two questions here:

  • Am I doing something wrong?
  • Is there any viable unique counter rest generation algorithm in Neo4j?

Neo4j version is 1.9RC1, thanks in advance!

4

1 回答 1

4

您遇到的问题是 neo4j 没有隐式读锁定。所以有时会发生以下情况:

  1. 查询 1 开始
  2. 查询 1 将值读取counter为 3
  3. 查询 1 将counter值设置为 3+1 = 4
  4. 查询 2 开始
  5. 查询 2 读取counter值为 4
  6. 查询 2 将counter值设置为 4+1 = 5

这就是有时会发生的情况:

  1. 查询 1 开始
  2. 查询 2 开始
  3. 查询 1 将值读取counter为 3
  4. 查询 2 将值读取counter为 3
  5. 查询 1 将counter值设置为 3+1 = 4
  6. 查询 2 将counter值设置为 3+1 = 4

在读锁定数据库(如大多数 SQL 服务器)中,情况 #2 不可能发生。查询 2 将启动,然后将阻塞,直到查询 1 提交或回滚。

可能有一种方法可以显式设置读取锁,但不能通过 REST API。事务API看起来很有希望,尽管我不完全确定它能否为您提供您想要的东西,而且,REST 不支持它。

于 2013-04-24T16:19:30.340 回答