java - Neo4j 2.0中如何优雅地处理NotFoundException?

标签 java cypher neo4j

我们一厢情愿地认为,在 Neo4j 2.0 中,并发查询和删除节点将不再抛出 NotFoundException。我们之前使用 Neo4j 1.9.3 的系统充满了处理此异常的检查(非常丑陋的代码)。 有没有更好的方法来处理 Neo4j 2.0 或管道中的 NotFoundException(如果没有消除)?

堆栈跟踪:

org.neo4j.graphdb.NotFoundException: Node 2432 not found
    at org.neo4j.kernel.impl.core.NodeManager.getNodeForProxy(NodeManager.java:425)
    at org.neo4j.kernel.impl.api.state.OldTxStateBridgeImpl.deleteNode(OldTxStateBridgeImpl.java:111)
    at org.neo4j.kernel.impl.api.state.TxStateImpl.nodeDoDelete(TxStateImpl.java:250)
    at org.neo4j.kernel.impl.api.StateHandlingStatementOperations.nodeDelete(StateHandlingStatementOperations.java:100)
    at org.neo4j.kernel.impl.api.ConstraintEnforcingEntityOperations.nodeDelete(ConstraintEnforcingEntityOperations.java:140)
    at org.neo4j.kernel.impl.api.LockingStatementOperations.nodeDelete(LockingStatementOperations.java:196)
    at org.neo4j.kernel.impl.api.OperationsFacade.nodeDelete(OperationsFacade.java:428)
    at org.neo4j.cypher.internal.spi.v2_0.TransactionBoundExecutionContext$NodeOperations.delete(TransactionBoundExecutionContext.scala:132)
    at org.neo4j.cypher.internal.spi.v2_0.TransactionBoundExecutionContext$NodeOperations.delete(TransactionBoundExecutionContext.scala:130)
    at org.neo4j.cypher.internal.compiler.v2_0.spi.DelegatingOperations.delete(DelegatingQueryContext.scala:92)
    at org.neo4j.cypher.internal.compiler.v2_0.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations.org$neo4j$cypher$internal$compiler$v2_0$spi$ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$super$delete(ExceptionTranslatingQueryContext.scala:118)
    at org.neo4j.cypher.internal.compiler.v2_0.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$anonfun$delete$1.apply$mcV$sp(ExceptionTranslatingQueryContext.scala:118)
    at org.neo4j.cypher.internal.compiler.v2_0.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$anonfun$delete$1.apply(ExceptionTranslatingQueryContext.scala:118)
    at org.neo4j.cypher.internal.compiler.v2_0.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$anonfun$delete$1.apply(ExceptionTranslatingQueryContext.scala:118)
    at org.neo4j.cypher.internal.compiler.v2_0.spi.ExceptionTranslatingQueryContext.org$neo4j$cypher$internal$compiler$v2_0$spi$ExceptionTranslatingQueryContext$$translateException(ExceptionTranslatingQueryContext.scala:149)
    at org.neo4j.cypher.internal.compiler.v2_0.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations.delete(ExceptionTranslatingQueryContext.scala:118)
    at org.neo4j.cypher.internal.compiler.v2_0.spi.UpdateCountingQueryContext$CountingOps.delete(UpdateCountingQueryContext.scala:118)
    at org.neo4j.cypher.internal.compiler.v2_0.mutation.DeleteEntityAction.org$neo4j$cypher$internal$compiler$v2_0$mutation$DeleteEntityAction$$delete(DeleteEntityAction.scala:50)
    at org.neo4j.cypher.internal.compiler.v2_0.mutation.DeleteEntityAction.exec(DeleteEntityAction.scala:36)
    at org.neo4j.cypher.internal.compiler.v2_0.pipes.ExecuteUpdateCommandsPipe.org$neo4j$cypher$internal$compiler$v2_0$pipes$ExecuteUpdateCommandsPipe$$exec(ExecuteUpdateCommandsPipe.scala:56)
    at org.neo4j.cypher.internal.compiler.v2_0.pipes.ExecuteUpdateCommandsPipe$$anonfun$org$neo4j$cypher$internal$compiler$v2_0$pipes$ExecuteUpdateCommandsPipe$$executeMutationCommands$1$$anonfun$apply$2.apply(ExecuteUpdateCommandsPipe.scala:45)
    at org.neo4j.cypher.internal.compiler.v2_0.pipes.ExecuteUpdateCommandsPipe$$anonfun$org$neo4j$cypher$internal$compiler$v2_0$pipes$ExecuteUpdateCommandsPipe$$executeMutationCommands$1$$anonfun$apply$2.apply(ExecuteUpdateCommandsPipe.scala:45)
    at scala.collection.Iterator$$anon$13.hasNext(Iterator.scala:371)
    at scala.collection.Iterator$$anon$13.hasNext(Iterator.scala:371)
    at org.neo4j.cypher.internal.compiler.v2_0.pipes.EmptyResultPipe.internalCreateResults(EmptyResultPipe.scala:28)
    at org.neo4j.cypher.internal.compiler.v2_0.pipes.PipeWithSource.createResults(Pipe.scala:71)
    at org.neo4j.cypher.internal.compiler.v2_0.executionplan.ExecutionPlanBuilder.org$neo4j$cypher$internal$compiler$v2_0$executionplan$ExecutionPlanBuilder$$prepareStateAndResult(ExecutionPlanBuilder.scala:149)
    at org.neo4j.cypher.internal.compiler.v2_0.executionplan.ExecutionPlanBuilder$$anonfun$3.apply(ExecutionPlanBuilder.scala:136)
    at org.neo4j.cypher.internal.compiler.v2_0.executionplan.ExecutionPlanBuilder$$anonfun$3.apply(ExecutionPlanBuilder.scala:135)
    at org.neo4j.cypher.internal.compiler.v2_0.executionplan.ExecutionPlanBuilder$$anon$6.execute(ExecutionPlanBuilder.scala:50)
    at org.neo4j.cypher.internal.ExecutionPlanWrapperForV2_0.execute(CypherCompiler.scala:93)
    at org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:61)
    at org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:55)
    at org.neo4j.cypher.javacompat.ExecutionEngine.execute(ExecutionEngine.java:65)
    at net.ahm.graph.ConcurrDeleteLab$1.run(ConcurrDeleteLab.java:65)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:744

模拟问题的源代码:

package net.ahm.graph;

import java.io.File;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;
import org.neo4j.cypher.javacompat.ExecutionEngine;
import org.neo4j.cypher.javacompat.ExecutionResult;
import org.neo4j.graphdb.DynamicLabel;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
import org.neo4j.graphdb.factory.GraphDatabaseSettings;
import org.neo4j.graphdb.schema.IndexDefinition;
import org.neo4j.graphdb.schema.Schema;
import org.neo4j.kernel.impl.util.FileUtils;
import org.neo4j.kernel.impl.util.StringLogger;

public class ConcurrDeleteLab {
    private static final Logger LOG = Logger.getLogger(CypherLab.class);
    private final static int CONCURRENCY = 4;

    public static void main(String[] args) throws Exception {
        FileUtils.deleteRecursively(new File("graphdb"));
        final GraphDatabaseService graphDb = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder("graphdb")
                .setConfig(GraphDatabaseSettings.use_memory_mapped_buffers, "true").setConfig(GraphDatabaseSettings.cache_type, "strong")
                .newGraphDatabase();
        registerShutdownHook(graphDb);
        LOG.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>> NUMBER OF PARALLEL CYPHERS: " + CONCURRENCY);
        LOG.info(">>>> STARTED GRAPHDB");
        createIndex("Entity", "name", graphDb);
        try (Transaction tx = graphDb.beginTx()) {
            for (int i = 0; i < 100000; i++) {
                Node child = graphDb.createNode(DynamicLabel.label("Entity"));
                child.setProperty("name", "entity" + i);
            }
            tx.success();
        }
        LOG.info(">>>> CREATED NODES");
        final ExecutionEngine engine = new ExecutionEngine(graphDb, StringLogger.SYSTEM);
        for (int i = 0; i < 4; i++) {
            try (Transaction tx = graphDb.beginTx()) {
                ExecutionResult result = engine.execute("match (n:Entity) return n.name");
                for (Map<String, Object> row : result) {
                    assert ((String) row.get("n.name") != null);
                }
                tx.success();
            }
        }
        LOG.info(">>>> WARMED UP");
        ExecutorService es = Executors.newFixedThreadPool(CONCURRENCY);
        final CountDownLatch cdl = new CountDownLatch(CONCURRENCY);
        for (int i = 0; i < CONCURRENCY; i++) {
            if (i % 2 == 0) {
                es.execute(new Runnable() {
                    @Override
                    public void run() {
                        try (Transaction tx = graphDb.beginTx()) {
                            long time = System.currentTimeMillis();
                            engine.execute("match (n:Entity) delete n");
                            LOG.info(">>>> CYPHER TOOK: " + (System.currentTimeMillis() - time) + " m-secs");
                            tx.success();
                        } catch (Throwable t) {
                            LOG.error(t);
                            t.printStackTrace();
                        } finally {
                            cdl.countDown();
                        }
                    }
                });
            } else {
                es.execute(new Runnable() {
                    @Override
                    public void run() {
                        try (Transaction tx = graphDb.beginTx()) {
                            long time = System.currentTimeMillis();
                            ExecutionResult result = engine.execute("match (n:Entity) return n.name");
                            LOG.info(">>>> CYPHER TOOK: " + (System.currentTimeMillis() - time) + " m-secs");
                            int count = 0;
                            time = System.currentTimeMillis();
                            for (Map<String, Object> row : result) {
                                assert ((String) row.get("n.name") != null);
                                count++;
                            }
                            LOG.info(">>>> GETTING RESULTS TOOK: " + (System.currentTimeMillis() - time) + " m-secs");
                            tx.success();
                            LOG.info(">>>> CYPHER RETURNED ROWS: " + count);
                        } catch (Throwable t) {
                            LOG.error(t);
                            t.printStackTrace();
                        } finally {
                            cdl.countDown();
                        }
                    }
                });
            }
        }
        cdl.await();
        es.shutdown();
    }

    private static void createIndex(String label, String propertyName, GraphDatabaseService graphDb) {
        IndexDefinition indexDefinition;
        try (Transaction tx = graphDb.beginTx()) {
            Schema schema = graphDb.schema();
            indexDefinition = schema.indexFor(DynamicLabel.label(label)).on(propertyName).create();
            tx.success();
        }
        try (Transaction tx = graphDb.beginTx()) {
            Schema schema = graphDb.schema();
            schema.awaitIndexOnline(indexDefinition, 10, TimeUnit.SECONDS);
            tx.success();
        }
    }

    private static void registerShutdownHook(final GraphDatabaseService graphDb) {
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                LOG.info("### GRAPHDB SHUTDOWNHOOK INVOKED !!!");
                graphDb.shutdown();
            }
        });
    }

}

最佳答案

目前看来没有更好的选择。 2012 年曾在此报告过此问题: https://github.com/neo4j/neo4j/issues/37

关于java - Neo4j 2.0中如何优雅地处理NotFoundException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21385630/

相关文章:

java - 光栅与绘制(g),绘制组件(g)

java - 将数据类型 TYPE_4BYTE_ABGR 的字节数组转换为 BufferedImage

java - Red5 无法解析 bean 引用

java - java.util.concurrent.ConcurrentSkipListSet 的替代品

Neo4j/密码 : inline conversion of string to a map

neo4j - 不能用冒号查询属性

neo4j - 设置标签 : pass label name as parameter

Neo4j可以在关系之间建立关系吗?

neo4j - neo4j 属性区分大小写吗?

docker - 无法在 GitLab CI docker-in-docker 中针对 neo4j 数据库运行测试