2017-08-15 25 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的节点上的伟大工程。

这很容易推理,并根据需要进行扩展。

相关问题