在promisized IndexedDB事务中不回滚数据操作

djp7away  于 2022-12-09  发布在  IndexedDB
关注(0)|答案(1)|浏览(175)

当我调用函数saveDamage()时,在函数末尾的Promise.all()中发生异常。我希望前面的所有操作都能回滚,但它们没有。请问我做错了什么?谢谢!

saveDamage(damage) {
  return this.transaction('rw', [
    this.DAMAGE_STORE_NAME,
    this.DAMAGE_IMAGE_DATA_STORE_NAME,
    this.DAMAGE_IMAGE_DATA_TEMP_STORE_NAME
  ], (tx) => {
    let deletePromise = (damage.id)
        ? this._deleteDamage(tx, damage.id)
        : Promise.resolve();
    return deletePromise.then(() => {
      // Copy temporary image data of damage into permanent location and update their IDs
      let copyPromises = this._getDamageImageFields(damage).map(field => {
        return this._copyObject(tx, this.DAMAGE_IMAGE_DATA_TEMP_STORE_NAME, this.DAMAGE_IMAGE_DATA_STORE_NAME, field.value.imageDataId)
            .then(id => field.value.imageDataId = id)
      });
      return Promise.all(copyPromises)
          // Save damage
          /* The exception occurs inside _saveObject(). Previous DB operations are not rolled back. */
          .then(() => this._saveObject(tx, this.DAMAGE_STORE_NAME, damage, damage.id)) 
          .then(id => damage.id = id)
          // Delete temporary image data
          .then(() => this._clearStore(tx, this.DAMAGE_IMAGE_DATA_TEMP_STORE_NAME));
    });
  });
}

transaction(mode, storeNames, executorFnc) {
  let tx = this._db.transaction(this._transactionStoreNames(storeNames), this._transactionMode(mode));
  tx.onabort = (event) => reject("Transaction failed: " + event.target.errorCode);
  return executorFnc(tx);
}

_deleteDamage(tx, id) {
  // Fetch damage from DB
  return this._getObject(tx, this.DAMAGE_STORE_NAME, id).then(damage => {
    // Delete all big image data
    let promises = this._getIdsOfDamageImageData(damage)
        .map(imageDataId => this._deleteObject(tx, this.DAMAGE_IMAGE_DATA_STORE_NAME, imageDataId));
    // Delete damage itself
    promises.push(this._deleteObject(tx, this.DAMAGE_STORE_NAME, id));
    return Promise.all(promises);
  });
}

_deleteObject(tx, storeName, id) {
  return new Promise((resolve, reject) => {
    let result = tx.objectStore(storeName).delete(id);
    result.onsuccess = (event) => resolve();
    result.onerror = (event) => reject(event);
  });
}

_copyObject(tx, sourceStoreName, targetStoreName, id) {
  return this._getObject(tx, sourceStoreName, id)
      .then(obj => this._saveObject(tx, targetStoreName, obj));
}

_saveObject(tx, storeName, object, id) {
  return new Promise((resolve, reject) => {
    let store = tx.objectStore(storeName);
    let result = store.put(object, id);
    result.onsuccess = (event) => resolve(event.target.result /* object id */);
    result.onerror = (event) => reject(event);
  });
}

例外情况是(我知道如何修复它):

Uncaught (in promise) DOMException: Failed to execute 'put' on 'IDBObjectStore': The object store uses in-line keys and the key parameter was provided.

编辑:经过一些实验,我了解到只要我退出成功处理程序,并且没有未完成的成功处理程序,那么事务就会提交。看起来像是在“then”函数中发出的操作在另一个事务中执行,因为“then”是作为退出成功处理程序时返回已解决承诺的结果执行的。我发现在单个事务中执行相关操作的唯一方法是使用普通的成功处理程序。但是,当下一步操作依赖于当前操作的结果时,使用普通的成功处理程序会变得很困难。例如,当我需要删除存储在存储器'a'中对象'A',而存储在存储器'b'中有很多子对象'B'时,在这种情况下,我需要先提取对象'A',然后逐个删除子对象'B',这需要动态生成处理代码,我不敢相信做这些基本事情这么难,所以我怀疑我还遗漏了什么。

fbcarpbf

fbcarpbf1#

1.这个错误意味着id是未定义的,我想在_saveObject
1.如果您的Promise代表个别交易,则Promise.all数组中在错误发生之前已确认的所有交易都将已经确认,而不论Promise.all Promise是否已被拒绝。请在单一交易中执行所有数据库作业,以便在任何一项作业失败时完成回复。

相关问题