Aran go beginTransaction () не откатывается с помощью trx.abort () - PullRequest
0 голосов
/ 21 января 2020

У меня трудности с arangodb.beginTransaction(). В моих тестах создание транзакции, вызов функции через trx.run() API и затем отмена trx не откатывает изменения данных в базе данных. Мне неясно, что происходит, и документация крайне скудная. Эта документация довольно зловещая, но также очень расплывчатая:

Если данная функция содержит асинхронные логики c, в транзакции будет выполняться только синхронная часть функции. Например, при использовании async / await в транзакции будет запускаться только код до первого await.

Как насчет вложенного async / await внутри вызываемой функции asyn c? Например, если у меня есть это:

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() выполняться внутри транзакции или нет?

1 Ответ

1 голос
/ 22 января 2020

Я автор арана gojs. Для потомков я хотел бы уточнить, что этот ответ о aran gojs 6, который является текущим выпуском aran gojs на момент написания этой статьи и версии, в которой впервые была добавлена ​​поддержка потоковой передачи. сделки. API может измениться в будущих версиях, хотя в настоящее время нет планов сделать это.

Из-за того, как работают транзакции (по состоянию на gojs 6), вам необходимо обратить особое внимание на предостережение упоминается в документации для метода run :

Если данная функция содержит асинхронные логики c, в транзакции будет выполняться только синхронная часть функции , Например, при использовании async / await в транзакции будет выполняться только код до первого await. Обратите внимание на приведенные ниже примеры.

Другими словами, функции 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 устанавливает весь драйвер в «режим транзакции», выполняет данную функцию и затем отключает «режим транзакции» после его выполнения, чтобы не связанный код случайно не запустился в транзакции.

Недостаток этого подхода заключается в том, что если функция asyn c и содержит несколько операторов await, в транзакции будет выполняться только код, предшествующий и включающий в себя первый await. В вашем коде это означает, что «режим транзакции» отключен после возврата this.getObjectTypeFromId(id). Если этот метод сам содержит несколько await выражений, опять-таки только первое будет частью транзакции (и т. Д.).

Надеюсь, это устранит некоторую путаницу.

...