Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/neo4j/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Neo4J的锁紧机构_Neo4j_Locking_Atomicity - Fatal编程技术网

Neo4J的锁紧机构

Neo4J的锁紧机构,neo4j,locking,atomicity,Neo4j,Locking,Atomicity,我在我的应用程序中发现了一个并发问题,在Neo4J v2.2.5中,有两个线程试图在同一时间对同一节点或关系执行写操作 我用简单的方法重现了这个问题: 下载并导入示例neo4j电影数据库: 由于数据库很旧,因此您必须在conf/neo4j.properties中添加allow_store_upgrade=true,以启用自动数据库升级 启动neo4j并在neo4jshell上运行此查询: match (a:Actor {name: "Claude Jade"}), (m:Movie) merge

我在我的应用程序中发现了一个并发问题,在Neo4J v2.2.5中,有两个线程试图在同一时间对同一节点或关系执行写操作

我用简单的方法重现了这个问题:

  • 下载并导入示例neo4j电影数据库: 由于数据库很旧,因此您必须在
    conf/neo4j.properties
    中添加
    allow_store_upgrade=true
    ,以启用自动数据库升级

  • 启动neo4j并在neo4jshell上运行此查询:

    match (a:Actor {name: "Claude Jade"}), (m:Movie)
    merge (a)-[:ACTS_IN]->(m);
    
    这将创建从“Claude Jade”演员到所有电影节点的角色关系。这样做的原因是为了使删除“Claude Jade”参与者节点过程(参见下面的第4条)更长,因此并发问题发生的可能性更大

  • 如果您还没有curl命令行程序,请下载它。我们将使用curl将查询发送到neo4j

  • 创建包含以下内容的bash脚本文件(文件名由您决定):

    #!/bin/bash
    
    curl -XPOST http://localhost:7474/db/data/transaction/commit -H "Content-Type: application/json" -d '{"statements" : [ {"statement" : "MATCH (n:Actor {name: \"Claude Jade\"}) OPTIONAL MATCH (n)-[r]-() DELETE n, r"} ]}' &
    curl -XPOST http://localhost:7474/db/data/transaction/commit -H "Content-Type: application/json" -d '{"statements" : [ {"statement" : "MATCH (n:Actor {name: \"Claude Jade\"}) CREATE (n)-[:ACTS_IN]->(m:Movie {title: \"Hello World\"}) RETURN m"} ]}' &
    
    wait
    
    这将并行运行两个curl进程,其中第一个进程将尝试删除“Claude Jade”演员及其所有关系,第二个进程将尝试创建与“Claude Jade”演员相关的新动作

  • 在bash上运行脚本文件,例如
    $./test.sh

  • 以下是我得到的结果:

    {
        "results" : [{
                "columns" : ["m"],
                "data" : [{
                        "row" : [{
                                "title" : "Hello World"
                            }
                        ]
                    }
                ]
            }
        ],
        "errors" : []
    } {
        "results" : [{
                "columns" : [],
                "data" : []
            }
        ],
        "errors" : [{
                "code" : "Neo.DatabaseError.Transaction.CouldNotCommit",
                "message" : "org.neo4j.kernel.api.exceptions.TransactionFailureException: Node record Node[3150,used=false,group=55,prop=-1,labels=Inline(0x0:[]),light] still has relationships",
                "stackTrace" : "java.lang.RuntimeException: org.neo4j.kernel.api.exceptions.TransactionFailureException: Node record Node[3150,used=false,group=55,prop=-1,labels=Inline(0x0:[]),light] still has relationships\r\n\tat org.neo4j.server.rest.transactional.TransitionalTxManagementKernelTransaction.commit(TransitionalTxManagementKernelTransaction.java:87)\r\n\tat org.neo4j.server.rest.transactional.TransactionHandle.closeContextAndCollectErrors(TransactionHandle.java:278)\r\n\tat 
                ...
    
    注意:如果没有看到任何事务错误,则必须重新导入电影数据库并重新运行上述步骤

    因此,从我所看到的情况来看,删除失败是因为它试图删除Actor节点及其在关系中的所有ACTS\u,它首先进行匹配查询(
    MATCH(n:Actor{name:\'Claude Jade\\”})可选匹配(n)-[r]-()
    ),但在执行
    删除n,r
    )之前,第二个进程设法将新的ACTS_插入到Actor节点,这就是删除失败的原因,因为当它尝试执行删除时,Actor已经添加了一个新的关系


    我想知道Neo4J上是否有可以用来防止此问题的锁定机制?

    您正在观察一个经典的竞速条件。为了防止出现这种情况,您需要在
    Claude
    节点上获取一个锁。Cypher没有显式抓取锁的语法,所以我们只是将一个伪属性设置为第一个操作,并在最后删除该属性-这有抓取锁的副作用。因此,改变你的两种说法:

    MATCH (n:Actor {name: "Claude Jade"}) 
    SET n._fake = 1   // grabs the lock as first action
    WITH n
    OPTIONAL MATCH (n)-[r]-() 
    DELETE n, r
    
    MATCH (n:Actor {name: "Claude Jade"}) 
    SET n._fake = 1 // grab the lock early
    CREATE (n)-[:ACTS_IN]->(m:Movie {title: "Hello World"}) 
    REMOVE n._fake   // get rid of fake property
    RETURN m
    

    您好,感谢您的解决方案,我已经尝试过了,有时它可以工作,但有时我在第二个curl进程(在关系中创建新的ACTS_)中出错:
    {“results”:[],“errors”:[{“code”:“Neo.ClientError.Statement.EntityNotFound”,“message”:“无法加载id为3150的节点”。}]}
    使用fake属性可以有效地序列化这两条语句,因为另一条语句必须等待第一条语句提交。由于两条语句同时启动,因此无法确定哪一条语句首先获取锁。如果delete语句首先选择,它将删除node和rels,第二个匹配将失败(因为节点已消失)。如果delete语句首先运行,第二个匹配过程确实将失败,但它不应返回错误,而应返回空数据。我想发生的事情是当第二个进程遇到
    SET n._fake=1
    行时,它停止了查询执行,直到第一个进程释放了锁。然后,当它被释放时,它试图再次将查询执行恢复到下一行:
    CREATE(n)-[:ACTS_IN]->(m:Movie{title:\'Hello World\'})
    ,但是节点
    n
    已经被第一个进程删除,这就是为什么错误
    无法加载id为的节点…
    。您是对的。在这种情况下,您应该在另一个不受更改影响的节点上获取一个锁。可以创建一个特定的Technical lock节点:
    create(:lock)
    ,并在该节点上设置/删除假属性。每个需要锁的语句都将以
    MATCH(l:lock)SET l开头。_fake=1和l。。。。。。移除l.(u fake
    我还遇到了需要手动锁定的问题。Neo4j流行的APOC插件有一系列可通过Cypher调用的显式锁定过程: