当前位置 : 主页 > 网页制作 > Nodejs >

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

来源:互联网 收集:自由互联 发布时间:2021-06-16
我很难解释Neo4j关于交易的文档.他们的文档似乎表明倾向于这样做,而不是明确声明tx.commit()和tx.rollback(). 对于多语句事务和neo4j驱动程序,这看起来是最佳实践吗? const register = async (co
我很难解释Neo4j关于交易的文档.他们的文档似乎表明倾向于这样做,而不是明确声明tx.commit()和tx.rollback().

对于多语句事务和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,则此类事务会很有效.

它很容易推理,并根据需要进行扩展.

网友评论