2017-08-15 65 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. 使用try/catch塊後(以使適當範圍在catch塊)
  4. 在try塊執行查詢
  5. 回滾在catch塊

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的,你應該換他們的Cypher查詢與toInteger(),所以它們能夠被正確解析內部。

我還包括查詢參數的例子以及如何使用它們。我發現它清理了一些代碼。

除此之外,你基本上可以鏈,只要你想在交易中儘可能多的查詢,但要記住兩兩件事:

  1. 的Neo4j寫鎖定事務中涉及的所有節點,因此,如果你有幾個處理同一節點上的所有執行操作,您將看到只有一個進程可以一次完成一個事務。我們制定了自己的業務邏輯來處理寫入問題,並選擇不使用事務。到目前爲止,它工作得非常好,編寫了10萬個節點,並在大約30秒內創建了100,000個關係,分佈在10個進程中。交易中花費了10倍的時間。我們使用UNWIND體驗沒有死鎖或競賽條件。
  2. 您必須等待tx.commit(),否則它不會在其進行會話之前進行提交。

我的看法是,這種類型的交易,如果你正在使用多語種(多個數據庫),並需要建立一個節點,然後寫一個文檔的MongoDB,然後設置蒙戈ID的節點上的偉大工程。

這很容易推理,並根據需要進行擴展。

相關問題