使用 IndexedDB,是否可以在 window.indexedDB.open 的 onsuccess 事件中创建对象存储?

With IndexedDB, is it possible to create an object store in the onsuccess event of the window.indexedDB.open?

我正在构建一个应用程序,我想在每次加载页面时尝试从数据库中重新提取数据。如果没有网络连接,那么我将使用存储在 IndexedDB 中的数据。

为此,我认为在 window.indexedDB.open 函数的 onsuccess 事件中清除我们现有的对象存储,然后使用新数据重新创建是有意义的。像这样:

var request = window.indexedDB.open("offlineInspections",1);
        
request.onsuccess = function(event){    
    db = request.result;
    //Check if connected to network
    //If yes, pull new data
    // TODO (will use AJAX to make a server call)
    
    //Check if current data exists
    //If yes, delete
    if(db.objectStoreNames.contains("user")){
        db.deleteObjectStore("user");
    }
        
    //Load new data
    var userStore = db.createObjectStore("user",{keyPath: "id"}); //Throws error
    var transaction = event.target.transaction;
    
    transaction.oncomplete = function(event){
        console.log('New user store created');
    }
}

当我尝试 运行 时,在上面提到的行中出现以下错误:

Uncaught DOMException: A mutation operation was attempted on a database that did not allow mutations.

您只能从 onupgradeneeded 事件处理函数中更改数据库的对象存储和索引,该函数在版本更改读写事务的上下文中运行。

onupgradeneeded 事件处理程序与成功打开请求事件处理程序不同。成功的打开事件处理程序不允许更改对象存储或索引。成功事件仅在升级事务完成后发生。到那个时候,您正在尝试对不允许突变(在版本更改事务的上下文之外)的数据库执行突变操作(对 create/delete 对象存储的命令)。

解决方案是使用 onupgradeneeded 处理程序:

var request = indexedDb.open(...);

request.onupgradeneeded = function(event) {
  // do database changes here, e.g.
  var db = event.target.result;
  db.createObjectStore(...);
};

request.onsuccess = function(event) {
  // do database reads/writes here
  // you cannot use createObjectStore here
};