Arango beginTransaction() 不回滚 trx.abort()
Arango beginTransaction() not rolling back with trx.abort()
我在使用 arangodb.beginTransaction()
时遇到了一些困难。在我的测试中,创建事务、通过 trx.run()
API 调用函数然后中止 trx
不会回滚数据库中的数据更改。我不清楚发生了什么,文档也非常稀少。有这个文档非常不祥,但也很模糊:
If the given function contains asynchronous logic, only the synchronous part of the function will be run in the transaction. E.g. when using async/await only the code up to the first await will run in the transaction.
在被调用的异步函数中嵌套 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()
是否会在事务内部执行?
我是 arangojs 的作者。对于后代,我想澄清一下这个答案是关于 arangojs 6 的,这是撰写本文时 arangojs 的当前版本,也是第一个添加对流式事务支持的版本。 API 可能会在未来的版本中发生变化,尽管目前没有这样做的计划。
由于事务的工作方式(自 arangojs 6 起),您需要特别注意 documentation for the run
method 中提到的警告:
If the given function contains asynchronous logic, only the synchronous part of the function will be run in the transaction. E.g. when using async/await only the code up to the first await will run in the transaction. Pay attention to the examples below.
换句话说,如果您只是将 async
函数包装在 trx.run
中,它们的行为可能不会正确。我建议将事务对象传递给每个函数,并将这些函数中的方法调用包装在 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
将整个驱动程序设置为 "transaction mode",执行给定的函数,然后在执行后禁用 "transaction mode",这样不相关的代码就不会意外 运行在交易中。
这种方法的缺点是,如果函数是异步的并且包含多个 await
语句,则只有引导到第一个 await
并包括第一个 await
的代码将是 运行交易。在您的代码中,这意味着 "transaction mode" 在 this.getObjectTypeFromId(id)
returns 之后被禁用。如果该方法本身包含多个 await
表达式,同样只有第一个将成为交易的一部分(依此类推)。
我希望这能消除一些困惑。
我在使用 arangodb.beginTransaction()
时遇到了一些困难。在我的测试中,创建事务、通过 trx.run()
API 调用函数然后中止 trx
不会回滚数据库中的数据更改。我不清楚发生了什么,文档也非常稀少。有这个文档非常不祥,但也很模糊:
If the given function contains asynchronous logic, only the synchronous part of the function will be run in the transaction. E.g. when using async/await only the code up to the first await will run in the transaction.
在被调用的异步函数中嵌套 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()
是否会在事务内部执行?
我是 arangojs 的作者。对于后代,我想澄清一下这个答案是关于 arangojs 6 的,这是撰写本文时 arangojs 的当前版本,也是第一个添加对流式事务支持的版本。 API 可能会在未来的版本中发生变化,尽管目前没有这样做的计划。
由于事务的工作方式(自 arangojs 6 起),您需要特别注意 documentation for the run
method 中提到的警告:
If the given function contains asynchronous logic, only the synchronous part of the function will be run in the transaction. E.g. when using async/await only the code up to the first await will run in the transaction. Pay attention to the examples below.
换句话说,如果您只是将 async
函数包装在 trx.run
中,它们的行为可能不会正确。我建议将事务对象传递给每个函数,并将这些函数中的方法调用包装在 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
将整个驱动程序设置为 "transaction mode",执行给定的函数,然后在执行后禁用 "transaction mode",这样不相关的代码就不会意外 运行在交易中。
这种方法的缺点是,如果函数是异步的并且包含多个 await
语句,则只有引导到第一个 await
并包括第一个 await
的代码将是 运行交易。在您的代码中,这意味着 "transaction mode" 在 this.getObjectTypeFromId(id)
returns 之后被禁用。如果该方法本身包含多个 await
表达式,同样只有第一个将成为交易的一部分(依此类推)。
我希望这能消除一些困惑。