这是用Neo4j编写多语句事务的正确方法吗?

我很难解释Neo4j关于事务的文档。 他们的文档似乎表明喜欢这样做,而不是显式声明tx.commit()tx.rollback()

这看起来是多语句交易和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 } } 

对于这篇长文章,我感到抱歉,但是我无法在任何地方find任何引用,所以社区需要这些数据。

在做了更多的工作之后,这是我们为多语句事务处理的语法:

  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,则应使用toInteger()将它们包含在Cypher查询中,以便正确parsing它们。

我还包括查询参数的例子以及如何使用它们。 我发现它清理了一些代码。

除此之外,基本上可以根据需要链接尽可能多的查询内容,但要记住两件事情:

  1. Neo4j在事务处理过程中locking了所有涉及的节点,所以如果你有几个进程都在同一个节点上执行操作,你将会看到一次只能有一个进程完成一个事务。 我们制定了自己的业务逻辑来处理写入问题,并select不使用事务。 到目前为止,它工作得非常好,编写了10万个节点,并在大约30秒内创build了10万个关系,分布在10个进程中。 在交易中花了10倍的时间。 我们没有经历使用UNWIND死锁或竞赛状况。
  2. 你必须等待tx.commit()否则在会话之前不会提交。

我的意见是,如果您使用Polyglot(多个数据库)并需要创build节点,然后将文档写入MongoDB,然后在该节点上设置Mongo ID,则此类事务处理效果很好。

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