IndexedDB:您可以手动发起版本更改事务吗?

IndexedDB: Can you manually initiate a version change transaction?

我正在编写一个 Chrome 扩展,它利用了 IndexedDB to store some information client side in an IDBObjectStore within an IDBDatabase

数据的性质使得我需要我的用户能够随心所欲地修改对象存储。 (添加新对象修改现有对象等)我正在通过设置页面完成此操作,到目前为止一切都很好。

当我想发布新版本的(默认)对象存储时,需要注意的是。如果我不关心覆盖我的用户数据,那么我可以处理 onupgradeneeded 事件,就像我在响应全新安装时触发它时处理它一样。这将是这样的:

var request = window.indexedDB.open(DB_NAME, CURRENT_DB_VERSION);
request.onupgradeneeded = upgrade;
function upgrade(event){
  var db = event.target.result;
  var objectStore = db.createObjectStore("domains", {keyPath: "id", autoIncrement: true});
  objectStore.createIndex("domain", "domain", {multiEntry: true });
  for(var i=0; i<tags.length; i++){
    objectStore.add(tags[i]);
    console.log("added " + tags[i]["domain"] + " to the IDBObjectStore 'domains' in the IDBDatabase 'Tags' (Format)");
  }
}

...但我很在意。

所以,我目前正在做的是在 upgrade(event) 函数中放置一个条件,用于检查 event.oldVersion 的真实性(在全新安装时为 0)。如果该值大于 0,那么我会打开一个新选项卡,其中包含一个选项页面,用户可以在其中选择他想要更新的对象。

现在是棘手的部分:此页面关闭后,我需要向后台页面发送一条消息,其中包含必要的升级信息。通常,我只会在我的侦听器中接收消息并使用提供的信息执行更新。然而,IDBDatabase.createObjectStore() 抛出一个 InvalidStateError 如果:

The method [is] not called from a versionchange transaction callback.

当我查看 IDBDatabase.transaction(storenames, mode) 的规范时,在 mode 参数描述中,它说:

versionchange mode can't be specified here.

所以,在我看来我需要触发一个 onupgradeneeded 事件,但除了事件本身之外,我还需要向事件处理程序传递一个附加参数,该参数包含它可以用来决定如何执行升级。

虽然我不知道该怎么做。

谁能给我一些见解?

您正在获取 InvalidStateError,因为您可能没有从 onupgradeneeded 事件处理程序调用 IDBDatabase.createObjectStore()。对于 IDB,所有对象存储的创建和操作都必须在 onupgradeneeded 事件处理程序内部或在触发 onupgradeneeded 之后发生。

如果我正确理解了您的要求,那么您不想在某些情况下覆盖用户现有的对象存储,为此您想在 onupgradeneeded 事件处理程序中传递一些信息以判断是否重新创建对象存储或在现有对象存储之上做一些修改。

我的建议是 - 拥有 2 个全局数组变量 DB_SCHEMA_DROP_QUERIESDB_SCHEMA_CREATE_QUERIES,您可以在使用 window.indexedDB.open(DB_NAME, CURRENT_DB_VERSION);

打开数据库之前使用 drop 和 create data 进行准备

然后有如下代码(我只是提醒一下),所以当你想 1. 创建一个新的数据库然后首先从数据库中删除所有现有的数据存储并创建新的(这意味着填充 DB_SCHEMA_DROP_QUERIESDB_SCHEMA_CREATE_QUERIES)。 2. 只需再添加一个对象存储然后只准备 DB_SCHEMA_CREATE_QUERIES 3. 修改现有的对象存储然后准备两个 DB_SCHEMA_DROP_QUERIESDB_SCHEMA_CREATE_QUERIES 但仅针对该特定对象存储

基本上我们正在努力实现的目标是使事物动态化,而不是像这样 db.createObjectStore("domains", {keyPath: "id", autoIncrement: true}); 创建硬编码数据存储。这也将帮助您摆脱维护版本记录。

var dropQueriesLength = DB_SCHEMA_DROP_QUERIES.length;
for(var i =0; i < dropQueriesLength; i++){
try{
    DB_HANDLER.deleteObjectStore(DB_SCHEMA_DROP_QUERIES[i].name);
} catch(e){

}
}

for(var i =0; i < DB_SCHEMA_CREATE_QUERIES.length; i++){
  var objectStore = null;
    if(DB_SCHEMA_CREATE_QUERIES[i].primaryKeyCol != null && DB_SCHEMA_CREATE_QUERIES[i].primaryKeyCol != undefined){
        objectStore = DB_HANDLER.createObjectStore(DB_SCHEMA_CREATE_QUERIES[i].name, { keyPath: DB_SCHEMA_CREATE_QUERIES[i].primaryKeyCol});
    }
}

触发升级式事务(版本更改事务)的唯一方法是打开具有更大版本号的连接。