2017-08-15 13 views
3

Neo4jのトランザクションに関するドキュメントを解釈するのに苦労しています。彼らの文書は、tx.commit()tx.rollback()と明示的に宣言するのではなく、の方法を優先しているようです。これは、Neo4jで複数の文のトランザクションを書き込む適切な方法ですか?

マルチステートメント取引やneo4j-driverに関しては、これがベストプラクティスに見えますか?ここ

const register = async (container, user) => { 
    const session = driver.session() 
    const timestamp = Date.now() 

    const saltRounds = 10 
    const pwd = await utils.bcrypt.hash(user.password, saltRounds) 

    try { 
     //Start registration transaction 
      const registerUser = session.writeTransaction(async (transaction) => { 
      const initialCommit = await transaction 
       .run(` 
        CREATE (p:Person { 
         email: '${user.email}', 
         tel: '${user.tel}', 
         pwd: '${pwd}', 
         created: '${timestamp}' 
        }) 
        RETURN p AS Person 
       `) 

      const initialResult = initialCommit.records 
       .map((x) => { 
        return { 
         id: x.get('Person').identity.low, 
         created: x.get('Person').properties.created 
        } 
       }) 
       .shift() 

      //Generate serial 
      const data = `${initialResult.id}${initialResult.created}` 
      const serial = crypto.sha256(data) 

      const finalCommit = await transaction 
       .run(` 
        MATCH (p:Person) 
        WHERE p.email = '${user.email}' 
        SET p.serialNumber = '${serial}' 
        RETURN p AS Person 
       `) 

      const finalResult = finalCommit.records 
       .map((x) => { 
        return { 
         serialNumber: x.get('Person').properties.serialNumber, 
         email: x.get('Person').properties.email, 
         tel: x.get('Person').properties.tel 
        } 
       }) 
       .shift() 

      //Merge both results for complete person data 
      return Object.assign({}, initialResult, finalResult) 
     }) 

     //Commit or rollback transaction 
     return registerUser 
      .then((commit) => { 
       session.close() 
       return commit 
      }) 
      .catch((rollback) => { 
       console.log(`Transaction problem: ${JSON.stringify(rollback, null, 2)}`) 
       throw [`reg1`] 
      }) 
    } catch (error) { 
    session.close() 
     throw error 
    } 
} 

論理の縮小版である:

const register = (user) => { 
    const session = driver.session() 
    const performTransaction = session.writeTransaction(async (tx) => { 

     const statementOne = await tx.run(queryOne) 
     const resultOne = statementOne.records.map((x) => x.get('node')).slice() 

     // Do some work that uses data from statementOne 

     const statementTwo = await tx.run(queryTwo) 
     const resultTwo = statementTwo.records.map((x) => x.get('node')).slice() 

     // Do final processing 

     return finalResult 
    }) 

    return performTransaction.then((commit) => { 
      session.close() 
      return commit 
    }).catch((rollback) => { 
      throw rollback 
    }) 
} 

のNeo4jの専門家、上記のコードはneo4j-driverの正しい使用は?

ので、私はむしろこれを行うだろうその多くの線形および同期:

const register = (user) => { 
    const session = driver.session() 
    const tx = session.beginTransaction() 

    const statementOne = await tx.run(queryOne) 
    const resultOne = statementOne.records.map((x) => x.get('node')).slice() 

    // Do some work that uses data from statementOne 

    const statementTwo = await tx.run(queryTwo) 
    const resultTwo = statementTwo.records.map((x) => x.get('node')).slice() 

    // Do final processing 
    const finalResult = { obj1, ...obj2 } 
    let success = true 

    if (success) { 
     tx.commit() 
     session.close() 
     return finalResult 
    } else { 
     tx.rollback() 
     session.close() 
     return false 
    } 
} 

私は長い記事のために申し訳ありませんが、しかし、コミュニティは、このデータを必要とするので、私は、どこでもすべての参照を見つけることができません。

答えて

0

はるかに仕事の後、これは我々が複数文のトランザクションのために定住している構文は次のとおりです。

  1. スタートセッション
  2. スタートトランザクション
  3. 使用することは適切なスコープを有効にするには、/(後にcatchブロックを試してみてくださいcatchブロック)に
  4. は、catchブロックで
  5. ロールバックtryブロックでクエリを実行し

const someQuery = async() => { 
    const session = Neo4J.session() 
    const tx = session.beginTransaction() 
    try { 
     const props = { 
      one: 'Bob', 
      two: 'Alice' 
     } 
     const tx1 = await tx 
      .run(` 
       MATCH (n:Node)-[r:REL]-(o:Other) 
       WHERE n.one = $props.one 
       AND n.two = $props.two 
       RETURN n AS One, o AS Two 
      `, { props }) 
      .then((result) => { 
       return { 
        data: '...' 
       } 
      }) 
      .catch((err) => { 
       throw 'Problem in first query. ' + e 
      }) 

     // Do some work using tx1 
     const updatedProps = { 
      _id: 3, 
      four: 'excellent' 
     } 

     const tx2 = await tx 
      .run(` 
       MATCH (n:Node) 
       WHERE id(n) = toInteger($updatedProps._id) 
       SET n.four = $updatedProps.four 
       RETURN n AS One, o AS Two 
      `, { updatedProps }) 
      .then((result) => { 
       return { 
        data: '...' 
       } 
      }) 
      .catch((err) => { 
       throw 'Problem in second query. ' + e 
      }) 

     // Do some work using tx2 
     if (problem) throw 'Rollback ASAP.' 

     await tx.commit 
     session.close() 
     return Object.assign({}, tx1, { tx2 }) 
    } catch (e) { 
     tx.rollback() 
     session.close() 
     throw 'someQuery# ' + e 
    } 
} 

私はちょうどあなたがのNeo4jに番号を渡している場合、あなたは彼らが正しく解析されるようにtoIntegerとサイファークエリ()内にそれらをラップする必要があることに注意します。

クエリパラメータの例と使用方法についても説明しました。私はそれがコードを少しきれいにすることが分かった。

それに加えて、あなたは基本的にあなたが望むようトランザクション内の鎖のように多くのクエリができますが、心の中で2つの物事を保つ:

  1. のNeo4jは書き込みロックを、関係するすべてのノードのトランザクション中に、あなたはいくつかを持っているので、もしは、同じノード上ですべての処理を実行すると、一度に1つのプロセスしかトランザクションを完了できないことがわかります。私たちは、書き込みの問題を処理する独自のビジネスロジックを作成し、トランザクションを使用しないことを選択しました。これまでのところ、100,000のノードを作成し、10のプロセスにわたって約30秒で100,000の関係を作成することは、これまで非常にうまくいっています。取引では10倍の時間がかかりました。 UNWINDを使用すると、デッドロックや競合状態は発生しません。
  2. tx.commit()を待つ必要があります。セッションを終了する前にコミットしないでください。

私の意見あなたはポリグロット(複数のデータベース)を使用して、ノードを作成する必要があり、その後にMongoDBに文書を書いて、そのノード上のモンゴIDを設定している場合、トランザクションのこのタイプは、素晴らしい作品ということです。

これは非常に簡単に理由を説明し、必要に応じて拡張します。

関連する問題