2016-08-19 2 views
0

ご注意とアドバイスを事前にお寄せいただきありがとうございます。問題の説明が十分に分かりやすいことを願っています。埋め込みJava APIを使用してNeo4j 2から3にアップグレードする際の問題:hasNextIOの例外

私は、Javaベースのプロジェクトを組み込みAPIのバージョン3にアップグレードしています。残念ながら、次のエラーが表示されます。

重大度:hasNextの例外:文が閉じられました。

コードは次のとおりですが、ここで説明します。私のアプリケーションコードとデータベースコード(この場合はNeo4j)の間に分離レイヤーを提供するために、私はDAOパターンを使用しています。私は定義しているユーザーレベルのイテレータの変数にfindNodesコールから戻ってきているResourceIteratorを割り当てています。十分に明確だと私は例外を取得しています理由を説明するようで、このページ(https://neo4j.com/docs/java-reference/current/javadocs/org/neo4j/graphdb/Transaction.html

All ResourceIterables that where returned from operations executed inside a transaction will be automatically closed when the transaction is committed or rolled back. Note however, that the ResourceIterator should be closed as soon as possible if you don't intend to exhaust the iterator

によります。しかし、後で使用するためにイテレータを返す方法がいくつかあります。少なくとも私はそう願っています。もう1つの選択肢は、すべてのノードをユーザーのメモリに格納して、ユーザーレベルのインターフェイスを反復処理できるようにすることです。これは少し問題になります。私は、このコード(GlobalGraphOperationsクラスを使用していた)はNeo4j 2で動作していたことに注意してください。しかしおそらくそれはNeo4j 2のバグでしたか?私はトランザクションをクローズしないようにしようとしました(またはトランザクションを使用していても)。

アイデア?

実際の問題の原因は次のとおりです。ノードを表すユーザー可視構造のイテレーターの定義です。例外を投げる行は、hasNextの呼び出しです。

public boolean hasNext() { 
     // Wrap the neo4j iterator 
     boolean hasN = false; 
     GraphDatabaseService theDB = Neo4jDAOFactory.getTheNetworkDB(); 
     Transaction tx = theDB.beginTx(); 
     try { 
      hasN = nodeIterator.hasNext(); 
     } catch (Exception e) { 
      // should send this back using the message logs eventually 
      this.logger.log (Level.SEVERE, "exception in hasNext: " + e.getMessage(), e); 
     } finally { 
      tx.close(); 
     } 
     return hasN; 
    } 

しかし、それはまた、見ずに意味をなさない:

public Iterator<NetworkNodeTransferObject> 
    getNetworkNodes(String nameSpace, String key, Object value){ 

    Neo4jNetworkNodeDAOIterator theIterator = null; 
    GraphDatabaseService theDB = Neo4jDAOFactory.getTheNetworkDB(); 
    Transaction tx = theDB.beginTx(); 
    try { 

     Label newLabel = Label.label(nameSpace); 
     Iterator<Node> neo4jNodeList = theDB.findNodes(newLabel, key, value); 
     theIterator = new Neo4jNetworkNodeDAOIterator(); 
     theIterator.nodeIterator = neo4jNodeList; 
    } catch (Exception e) { 
     // should send this back using the message logs eventually 
     this.logger.log (Level.SEVERE, "exception in getNetworkNodes: " + e.getMessage(), e); 
    } finally { 
     tx.close(); 
    } 

    return theIterator; 
} 

おかげ ハワード

答えて

0

私が最初にあなたのhasNext()の実装に対処します:あなたは、いくつかの中nodeIterator.hasNext()をラップすることはできませんその時点での新しいトランザクションは、そのトランザクションが作成されたトランザクションのコンテキストで使用されなければなりません。

だから、基本的にそれはあなたの取引の問題について、今以上

public boolean hasNext() { 
    return nodeIterator.hasNext(); 
} 

である必要はありません:イテレータを返すために、あなたは、少なくとも同じ長イテレータ自体としてオープントランザクションを維持する必要があります。それを行うための複数の方法があります。

  • あなたがgetNetworkNodes以上の呼び出し元に上位層、すなわちでトランザクションを管理することができますので、getNetworkNodesは、その作成
  • で自身に関係するトランザクションが存在することを期待していないでしょう

    の場合、トランザクションはユーザレベルのイテレータで、nodeIteratorの横に置くことができますが、確実に閉じることは難しい場合があります。あなたは常にトランザクションを閉じて、最後までイテレータを消費場合のいずれか、あなたは終了時またはエラー(それはおそらく、とにかく反復を中断しますので)トリックを行う必要があります到達したとき:

    public boolean hasNext() { 
        boolean hasN = nodeIterator.hasNext(); 
        if (!hasN) { 
         tx.close(); 
        } 
        return hasN; 
    } 
    
    public NetworkNodeTransferObject next() { 
        try { 
         Node node = nodeIterator.next(); 
         // Create the NetworkNodeTransferObject 
         return networkNodeTo; 
        } catch (RuntimeException e) { 
         tx.close(); 
         throw e; 
        } 
    } 
    
+0

を情報に感謝します。 1つのさらなる質問:トランザクションをイテレータに格納し、イテレータが最後まで消費されなかったとします。イテレータが範囲外になると、トランザクションは終了しますか?それに頼ることは合理的ですか? – HowardLander

+0

いいえ、それは絶対に閉じられません: 'Transaction'実装が' finalize() 'メソッドを実装してガベージコレクション中にトランザクションを閉じる機会を得る必要があり、それは本当に脆いです(GCオーバーヘッドを追加します)。イテレータ全体を消費したくない場合は、トランザクションを手動で閉じることができる必要があります。 Neo4jの 'ResourceIterable'のように、サブインターフェース' ResourceIterator extends Iterator、AutoCloseable'を作成し、それを明示的にまたはtry-with-resourcesブロックを介して閉じます。 –

関連する問題