我很难解释Neo4j关于交易的文档.他们的文档似乎表明倾向于这样做,而不是明确声明tx.commit()和tx.rollback(). 对于多语句事务和neo4j驱动程序,这看起来是最佳实践吗? const register = async (co
对于多语句事务和neo4j驱动程序,这看起来是最佳实践吗?
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 } }
Here is the reduced version of the logic:
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?
I would rather do this because its more linear and synchronous:
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 } }
对于长篇文章我很抱歉,但我无法在任何地方找到任何参考资料,因此社区需要这些数据.
经过更多的工作,这是我们为多语句事务确定的语法:>开始会话
>开始交易
>之后使用try / catch块(在catch块中启用适当的范围)
>在try块中执行查询
>在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查询中,以便正确解析它们.
我还包括了查询参数的示例以及如何使用它们.我发现它清理了一些代码.
除此之外,您基本上可以根据需要在事务中链接尽可能多的查询,但请记住两件事:
> Neo4j在事务期间对所有涉及的节点进行写锁定,因此如果您有多个进程都在同一节点上执行操作,您将看到一次只有一个进程可以完成一个事务.我们制定了自己的业务逻辑来处理写入问题,并选择甚至不使用事务.到目前为止,它运行良好,编写100,000个节点,并在大约30秒内创建100,000个关系,分布在10个进程中.在交易中花了10倍的时间.我们使用UNWIND没有遇到死锁或竞争条件.
>您必须等待tx.commit(),否则它将在核对会话之前提交.
我的观点是,如果您使用Polyglot(多个数据库)并且需要创建节点,然后将文档写入MongoDB然后在节点上设置Mongo ID,则此类事务会很有效.
它很容易推理,并根据需要进行扩展.