在承诺&关闭事务,它将新类添加到图形中 - 新的Tx没有看到模式中的类,尽管它是持久的

时间:2015-10-01 10:55:39

标签: java orientdb

我们在一段代码中保留一个图形,然后有另一个代码,试图检索它。我们用这个Spring bean打开我们的transacitons。任何想要访问数据库的人总是调用这个bean的getGraph()方法。

public class OrientDatabaseConnectionManager {
private OrientGraphFactory factory;

public OrientDatabaseConnectionManager(String path, String name, String pass) {
    factory = new OrientGraphFactory(path, name, pass).setupPool(1,10);
}

public OrientGraphFactory getFactory() {
    return factory;
}

public void setFactory(OrientGraphFactory factory) {
    this.factory = factory;
}


/**
 * Method returns graph instance from the factory's pool.
 * @return 
 */
public OrientGraph getGraph(){

    OrientGraph resultGraph = factory.getTx();
    resultGraph.setThreadMode(OrientBaseGraph.THREAD_MODE.ALWAYS_AUTOSET);
    return resultGraph;

}

}

(我无法完全理解thread_mode,但我认为它不应该与问题有关。)

持久保存图表的代码提交和关闭,如下所示:

OrientDatabaseConnectionManager connMan; //this is an injected bean from above.
public boolean saveGraphToOrientDB(
        SparseMultigraph<SocialVertex, SocialEdge> graph, String label) {
    boolean isSavedCorrectly = false;
    OrientGraph graphO = connMan.getGraph();
    try {
        graphDBinput.saveGraph(graph, label, graphO);
        // LOG System.out.println("Graph was saved with label "+label);
        isSavedCorrectly = true;
    } catch (AlreadyUsedGraphLabelException ex) {
        Logger.getLogger(GraphDBFacade.class.getName()).log(Level.SEVERE, null, ex);
    } finally {
        graphO.shutdown(); //calls .commit() automatically normally, but commit already happens inside.
    }
    return isSavedCorrectly;
}

这个提交工作得很好 - 数据总是保持不变,我每次都在orientdb管理界面中检查,第一个持久化图表总是可见的。值得注意的是,在保存期间,使用的标签定义了新类(因此根据我的理解修改了模式)并将其用于持久化图。

图表的检索看起来像这样:

@Override
public SocialGraph getSocialGraph(String label) {
    OrientGraph graph = connMan.getGraph();
    SocialGraph socialGraph = null;
    try {
        socialGraph = new SocialGraph(getAllSocialNodes(label, graph), getAllSocialEdges(label, graph));
    } catch (Exception e) {
        logger.error(e);
    } finally {
        graph.shutdown();
    }
    return socialGraph;
}

public List<Node> getAllSocialNodes(String label, OrientGraph graph) {
    return constructNodes(graphFilterMan.getAllNodesFromGraph(label, graph));
}

public Set<Vertex> getAllNodesFromGraph(String graphLabel, OrientGraph graph) {
    Set<Vertex> labelledGraph = new HashSet<>();
    try{
        Iterable<Vertex> configGraph = graph.getVerticesOfClass(graphLabel);
        for(Vertex v : configGraph){ //THE CODE CRASHES HERE, WITH "CLASS WITH NAME graphLabel DOES NOT EXIST
            labelledGraph.add(v);
        }
    } catch(Exception ex){
        logger.error(ex);
        graph.rollback();
    }   
    return labelledGraph;
}

所以问题是,当我们用一个新的类坚持一个新图时,比如说#34; graph01&#34;然后我们想要检索它,它没关系。之后,我们创建了一个&#34; graph02&#34;我们想要检索它,但它崩溃了,正如上面评论的那样 - OrientDb告诉你,那个类带有&#34; graph02&#34;名称不存在。

当时它确实存在于管理界面中,但是,当我调试时,在调用factory.getTx()后,该类实际上不在模式中

刚开始时,当我们从工厂获得一个事务图实例时,我们得到一个带有上下文的图形,其中rawGraph的底层数据库的元数据具有模式代理委托模式共享类没有新类,我可以看到它在数据库中提交。

或者在图片上: enter image description here

架构中应该还有一个类。之前持久化(并提交)的那个 - 也可以在orientDb管理界面中看到(不存在于变量中)

我认为正在发生的事情是,工厂从中获取事务的池在某种程度上缓存了模式。当我们添加一个新类时,它不会刷新模式。

当我们尝试获取新图时,为什么架构不显示新类?架构不会刷新吗?

我找到了here in schema documentation

  

注意:对架构的更改不是事务性的,因此请在事务外部执行它们。

那么我们应该在事务之外创建新类,然后我们会在上下文中获得模式的更新吗?

//也许我理解错误的概念 - 昨天我与OrientDb有联系,我将在已编写的代码中找出问题。

我们使用的Db是remote:localhost/socialGraph OrientDB版本1.7.4

2 个答案:

答案 0 :(得分:1)

我们在代码中注意到同一问题,在池化连接中架构更改不可见。

我们还有一种获得连接的工厂。我们所做的是保留一个模式版本号,每次我们有一些改变模式的操作时,我们都会计算数字,当打开一个新连接时,我们检查模式版本,如果它被更改。

更改架构后,我们重新加载架构,关闭池并重新创建它。该方法已被证明可以使用(我们目前的版本为2.0.15)。

以下是相关代码:

private static volatile int schemaVersion = -1;

private OPartitionedDatabasePool pool;

protected void createPool() {
    pool = new OPartitionedDatabasePool(getUrl(), getUsername(), getPassword());
}

@Override
public synchronized ODatabaseDocumentTx openDatabase() {
    ODatabaseDocumentTx db = pool.acquire();

    //DatabaseInfo is a simple class put in a static contect that holds the schema version. 
    DatabaseInfo databaseInfo = CurrentDatabaseInfo.getDatabaseInfo();
    ODocument document = db.load((ORID) databaseInfo.getId(), "schemaVersion:0", true);
    Integer version = document.field("schemaVersion");

    if (schemaVersion == -1) {
        schemaVersion = version;
    } else if (schemaVersion < version) {
        db.getMetadata().getSchema().reload();
        schemaVersion = version;
        pool.close();
        createPool();
        db = pool.acquire();
    }
    return db;
}

答案 1 :(得分:0)

最后问题是,我们有两个liferay项目,每个项目在WAR文件中都有自己的spring应用程序上下文,当我们在Liferay中将这些项目部署为portlet时,这两个项目创建了两个上下文,每个上下文都有一个OrientDatabaseConnectionManager。

在一个上下文中,架构正在被更改。即使我重置连接并重新加载模式,它也只发生在一个上下文中的连接管理器/工厂。检索图是在另一个项目的portlet中发生的,导致一个过时的模式(没有重新加载,因为重新加载发生在其他弹簧上下文中) - 因此错误。

所以你必须要小心 - 要么为所有portlet共享一个spring应用程序上下文和bean(通过拥有父应用程序上下文,you can read more about it here

OR

检查同一项目中架构的变化,稍后您将用它来检索数据。