2012-08-03 54 views
3

我刚刚开始使用Graph数据库,并认为最好学习neo4j。我有一个在应用程序中运行的嵌入式neo4j实例(基于JSF)。应用程序的用例主要是让我学习使用图形数据库的概念和陷阱,并帮助确定最佳方式(即嵌入式或独立式)。但是我的测试应用程序是一个非常基本的联系人应用程序,能够定义关系(即KNOWS,WORKS_WITH,WORKS_FOR等),并最终能够根据这些关系提供建议(即“你也许也知道”)。处理嵌入式neo4j内交易的最佳方式?

到目前为止,我已经有了基本的c.r.u.d操作,并且可以添加/删除关系。我的下一步将是实际开始遍历图(我认为)。但是我现在遇到的问题是一旦我与服务器的会话过期,我不能重新建立一个新的会话,而没有得到IllegalStateException错误,抱怨商店当前正在使用。我认为,这是因为我从来没有在neo4j实例上调用shutdown。所以这让我认为我处理交易的方式都是错误的,所以我希望有人能够纠正我的理解(或根据具体情况可能会误解)我应该如何解决这个问题。

下面是我的助手类的一些方法正被用来处理Web客户端和Neo4j的之间的操作:

public class NeoNodeUtils { 
private GraphDatabaseService graphDb; 

public NeoNodeUtils() { 
    setup(); 
} 

public void setup() { 
    GraphDatabaseFactory neoFactory = new GraphDatabaseFactory(); 
    setGraphDb(neoFactory.newEmbeddedDatabase("Morpheus")); 
    registerShutdownHook(); 
} 

public GraphDatabaseService getGraphDb() { 
    return graphDb; 
} 

public void setGraphDb(GraphDatabaseService graphDb) { 
    this.graphDb = graphDb; 
} 

public Node getNode(Long id) { 
    Transaction tx = getGraphDb().beginTx(); 
    Node node = null; 
    try { 
     node = getGraphDb().getNodeById(id); 
     tx.success(); 
    } catch (Exception e) { 
     tx.failure(); 
     e.printStackTrace(); 
    } finally { 
     tx.finish(); 
     return node; 
    } 
} 

public Node createNode() { 
    Transaction tx = getGraphDb().beginTx(); 
    Node node = null; 
    try { 
     node = graphDb.createNode(); 
     System.out.println("new nodeId = " + node.getId()); 
     tx.success(); 
    } catch (Exception e) { 
     tx.failure(); 
     e.printStackTrace(); 
    } finally { 
     tx.finish(); 
     return node; 
    } 
} 

public Node addNodeProperty(Node node, String propertyName, Object propertyValue) { 
    Transaction tx = getGraphDb().beginTx(); 
    try { 
     node.setProperty(propertyName, propertyValue); 
     tx.success(); 
    } catch (Exception e) { 
     tx.failure(); 
     e.printStackTrace(); 
    } finally { 
     tx.finish(); 
     return node; 
    } 
} 

public void shutDown() { 
    graphDb.shutdown(); 
} 

public void registerShutdownHook() { 
    Runtime.getRuntime().addShutdownHook(new Thread() { 
     @Override 
     public void run() { 
      graphDb.shutdown(); 
     } 
    }); 
} 
} 

每一个辅助方法,是相当多的结构作为getNode完全相同的方式(长ID )和createNode(),当然有些更多的逻辑,但没有什么非常复杂的,因为我只是想学习这一点。

因此,最后对我的问题:
*这是处理这些交易的正确方法吗?或者,我是否应该实施某种类型的交易管理器?
*另外,我应该在每次交易后调用关机吗?
*也许这应该在客户端会话级别而不是应用程序级别处理?

在服务器(http/jvm)重新启动之前(如果您熟悉jsf,applicationScope),这个类将一直保留在服务器内存中,因此在每次事务之后调用shutdown会有点矫枉过正。

编辑:我实际上在下面哪个答案上撕下来标记为接受,因为它们都在某种程度上回答我的问题。所以,如果你想知道为什么答案不被接受,那就是为什么。

回答

1

您的交易处理似乎很好。不,你不应该在每次交易后关闭。 只需通过一个单例处理neo4j数据库 - 从上面提到的内容来看,它看起来像这个类被重新实例化,这就是问题 - 它试图打开另一个连接到neo4j,这是不允许的。

+0

感谢您验证我对如何实现这一点的想法。 “它看起来像这个类被重新实例化,这就是问题” 是的,这是我开始接触的结论。我认为JSF处理applicationScope的方式是,如果应用程序没有任何活动,那么它将applicationScope序列化到磁盘,并且一旦有人发出请求,它将被反序列化并且结果被重新实例化。我正在寻找解决此问题的方法或拦截此行为的方法。如果这个任务太大,那么neo4j服务器的一个实例就会被安装。 – keithstric 2012-08-06 15:55:38

5

不要将GraphDatabaseService看作是SQLConnection或类似的,它是一个长期存在的实例,并且经常停止它会从长期存在的这种实例中获得很多好处,并且会产生大量不必要的额外开销。

你不需要像这样调用tx.failure()。一个简单的:

 
public Node createNode() { 
    Transaction tx = getGraphDb().beginTx(); 
    try { 
     Node node = graphDb.createNode(); 
     System.out.println("new nodeId = " + node.getId()); 
     tx.success(); 
     return node; 
    } finally { 
     tx.finish(); 
    } 
}

罚款,因为一个事务只被视为成功,如果success()被调用,否则会回滚。另外读取操作不需要在交易中完成,因此:

 
public Node getNode(Long id) { 
    return getGraphDb().getNodeById(id); 
} 

就足够了。

+0

感谢您的澄清,您是否有任何SQLConnection的例子? – keithstric 2012-08-06 15:50:11

+2

请注意,在Neo4j 2中,'finish'不赞成使用'close',它允许使用try-with-resources Java 7'语句。 – Tvaroh 2013-12-03 18:58:37

+0

那么如果我们创建一堆节点会发生什么,即使我们还没有提交它们,它们是否可以搜索? – WantIt 2016-05-29 02:59:25

3

由于Java 7自动关闭和Neo4j的2.0来处理事务的方式是:

因此,不再需要
try (Transaction tx = graphDb.beginTx()) 
{ 
    ... 

    tx.success(); 
} 

明确finish