ArangoDB Arango beginTransaction()未使用trx回滚,abort()

djmepvbi  于 2022-12-09  发布在  Go
关注(0)|答案(1)|浏览(157)

我在使用arangodb.beginTransaction()时遇到了一些困难。在我的测试中,创建一个事务,通过trx.run() API调用一个函数,然后中止trx并不回滚数据库上的数据更改。我不清楚发生了什么,文档也非常少。有这样一个文档非常不祥,但也非常模糊:
如果给定的函数包含异步逻辑,则只有函数的同步部分将在事务中运行。例如,当使用async/await时,只有第一个await之前的代码将在事务中运行。
在调用的async函数中嵌套async/await会怎样呢?例如,如果我有以下代码:

async runQuery(query) {
    try {
      const cursor = await this.arangodb.query(query)
      return cursor.all()
    } catch (error) {
      logger.error('ArangoDB query failed', { stack: error })
      throw error
    }
}

async touchDocument(id, revision) {
    const type = await this.getObjectTypeFromId(id)
    const collection = await this.getCollection(type, false, true)
    const idCollection = await this.getCollection(ID_COLLECTION, false, true)
    const touchAql = aql`
      LET permanentDocId = DOCUMENT(${idCollection}, ${id}).docId
      LET permanentDoc = MERGE( DOCUMENT(permanentDocId),  { _rev : ${revision} })
      UPDATE permanentDoc WITH permanentDoc in ${collection} OPTIONS { ignoreRevs: false } 
      RETURN NEW
    `
    return this.runQuery(touchAql)
}

trx.run(() => this.touchDocument(parentId, parentRevision))

this.arangodb.query()是否会在交易内执行?

edqdpe6u

edqdpe6u1#

我是arangojs的作者。我想澄清一下,这个答案是关于arangojs 6的,这是在撰写本文时arangojs的最新版本,也是第一个添加了流事务支持的版本。API可能会在未来的版本中改变,尽管目前还没有这样做的计划。
由于事务的工作方式(从arangojs 6开始),您需要特别注意run方法文档中提到的警告:
如果给定的函数包含异步逻辑,则只有函数的同步部分将在事务中运行。例如,使用async/await时,只有第一个await之前的代码将在事务中运行。请注意下面的示例。
换句话说,如果只是将async函数 Package 在trx.run中,它们可能无法正常工作。我建议将事务对象传递给每个函数,并将这些函数中的方法调用 Package 在trx.run中。
例如:

async runQuery(query, trx) {
    try {
      const cursor = await trx.run(() => this.arangodb.query(query))
      return trx.run(() => cursor.all())
    } catch (error) {
      logger.error('ArangoDB query failed', { stack: error })
      throw error
    }
}

async touchDocument(id, revision, trx) {
    const type = await this.getObjectTypeFromId(id, trx)
    const collection = await this.getCollection(type, false, true, trx)
    const idCollection = await this.getCollection(ID_COLLECTION, false, true, trx)
    const touchAql = aql`
      LET permanentDocId = DOCUMENT(${idCollection}, ${id}).docId
      LET permanentDoc = MERGE( DOCUMENT(permanentDocId),  { _rev : ${revision} })
      UPDATE permanentDoc WITH permanentDoc in ${collection} OPTIONS { ignoreRevs: false } 
      RETURN NEW
    `
    return this.runQuery(touchAql, trx)
}

this.touchDocument(parentId, parentRevision, trx)

这背后的原因是trx.run将整个驱动程序设置为“事务模式”,执行给定的函数,然后在执行后禁用“事务模式”,这样不相关的代码就不会意外地在事务中运行。
这种方法的缺点是,如果函数是异步的,并且包含多个await语句,则只有第一个await之前的代码(包括第一个await)才会在事务中运行。在您的代码中,这意味着在this.getObjectTypeFromId(id)返回后“事务模式”被禁用。如果该方法本身包含多个await表达式,同样,只有第一个将是事务的一部分(等等)。
我希望这能澄清一些混乱。

相关问题