填充许多 ObjectStore 时的 IndexedDB,错误:无法在“IDBDatabase”上执行“事务”:版本更改事务正在运行

Posted

技术标签:

【中文标题】填充许多 ObjectStore 时的 IndexedDB,错误:无法在“IDBDatabase”上执行“事务”:版本更改事务正在运行【英文标题】:IndexedDB when populating many ObjectStores, Error: Failed to execute 'transaction' on 'IDBDatabase': A version change transaction is running 【发布时间】:2017-07-11 21:09:05 【问题描述】:

优秀的@Josh 已经回答了关于填充 IndexedDB ObjectStores 时出现错误消息的类似问题:

Failed to execute 'transaction' on 'IDBDatabase': A version change transaction is running

答案适用于仅填充一个 ObjectStore 的情况。但是在我的情况下,我需要填充至少 5 个 ObjectStore。

我可以通过遍历一个包含创建和填充每个对象所需的所有数据的列表来创建和填充所有 ObjectStore。该脚本在大多数情况下都可以正常工作,但是我检测到了一个缺陷,因此每次执行都不是完美无瑕,而是在执行了一些执行后我收到了上述消息。

如答案中所述,该问题与执行时间有关。根据发布的解决方案,我修改了我的代码,以便在创建和填充的所有过程中使用相同的事务。但是执行的时候又出现了新的错误:

Uncaught TransactionInactiveError: Failed to execute 'put' on 'IDBObjectStore': The transaction has finished.

@Josh 同样是解决问题的人。

如何完美地填充最近创建的 ObjectStore,而不会出现任何以前的错误?代码如下:

 var db;
 function createPopulate(DB_NAME, DB_VERSION) 
   const datastores = [
   osName:'a', osEndpoint:'/a', osKeyPath:'id',....,
   osName:'b', osEndpoint:'/b', osKeyPath:'id',....,
   osName:'c', osEndpoint:'/c', osKeyPath:'id',....
   ];

   var request = indexedDB.open(DB_NAME, DB_VERSION);
   request.onupgradeneeded = function(e) 
     db = this.result;
     var tx = e.target.transaction;

     for (i in datastores) 
      // ObjectoStore created
      // Index created
      var customObjectStore = tx.objectStore(datastores[i].osName, "readwrite");
      popTable(customObjectStore, datastores[i].osEndpoint);
     
  ;

在函数内部,有 popTable 函数,它获取数据并填充给定的 ObjectStore,使用 fetch 函数,fetch API:

function poptable(parameter, endPoint) 
     fetchGet2(endPoint, populate, parameter);
        function populate(json, parameter) 
           for (var m in json) 
              parameter.add(json[m]);
           
        

运行代码时,我收到以下消息:

  DOMException: Failed to execute 'add' on 'IDBObjectStore': The transaction has finished.

如果脚本修改为执行popTable only oncomplete事件,报错信息为:

  DOMException: Failed to execute 'objectStore' on 'IDBTransaction': The transaction has finished.   at IDBTransaction.objectStore.transaction.oncomplete.

如何避免这些错误?

【问题讨论】:

【参考方案1】:

当您等待其他异步事件发生时,您无法保持事务打开,这就是您在 fetchGet2 中所做的事情。只要所有请求都完成,事务就会自动提交,这基本上意味着如果您有一个请求,您在打开事务后没有同步发出 在这些请求之一的事件处理程序中发出(可以任意嵌套),那么您的事务将在该请求执行之前提交。

您要么必须在向 IndexedDB 写入任何内容之前完成所有数据提取,要么必须为每次提取使用单独的事务。

【讨论】:

谢谢你的回答很清楚,你觉得使用同步抓取怎么样,比方说使用旧的 XHR? 它可以工作,但同步意味着阻塞,所以对性能不利。如果你在一个网络工作者中做这一切,我想这可能没问题。但是如果可能的话,最好不要在事务打开时执行其他异步操作。要么使用多个事务,要么重新组织您的代码,以便在事务开始之前运行其他异步内容。

以上是关于填充许多 ObjectStore 时的 IndexedDB,错误:无法在“IDBDatabase”上执行“事务”:版本更改事务正在运行的主要内容,如果未能解决你的问题,请参考以下文章

在哪里存储 objectstore 和 vwsession 对象

我们可以动态使用 set objectstore name 吗?

使用 iterrows() 时的持久性问题

从 HealthKit 中提取时的额外字符

ceph-objectstore-tool工具

删除自动填充输入时的黄色背景