我很难解释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,则此类事务会很有效.
它很容易推理,并根据需要进行扩展.
