索引数据库升级需要事件永远不会完成



在我的应用程序中,用户应该能够动态创建和删除对象存储。多亏了 indexedDB,此操作(为什么在世界上)只允许在升级需要

触发onupgradedneed后,索引数据库永远不会完成此请求,gc 永远不会收集此连接。

仅在现有数据库中创建和删除存储时出现问题。开始时所需的更新(创建数据库并创建第一个存储)永远不会产生任何问题。

在进行升级之前,我尝试关闭每个数据库连接,因为 2013 年的 Chromium 有一个错误报告,其中提到了这个问题(标记为已修复:https://bugs.chromium.org/p/chromium/issues/detail?id=242115)。

事实上,我没有找到有关此问题的任何实际信息,这使我假设我在代码:)中做错了什么 但是为什么有些浏览器只是做它们的工作?

这是我重现此错误的代码:

数据库.js

// Init IndexedDB
var dbversion;
var oStore;
var dbname = "UserName1"; // == Username
initDB();

function initDB() {
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction;
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange
if (!indexedDB) {
window.alert("Datenbanksupport im Browser fehlt !")
}else{
console.log("indexedDB: Supported !");
// >> first visit ?
var vCheck = indexedDB.open(dbname);
vCheck.onerror = errorHandler;
vCheck.onversionchange = function(ev) {
vCheck.close();
};
vCheck.onsuccess = function(event){
var db = vCheck.result;
dbversion = parseInt(localStorage.getItem("dbversion"));
if (!dbversion){
// -- maybe
dbversion = parseInt(db.version);
if (dbversion <= 1){
// -- definitely
var needUpgrade = false;
db.close();
var request = indexedDB.open(dbname, dbversion+1);
request.onerror = errorHandler;
request.onupgradeneeded = function(event){
console.log("indexedDB: start upgrade");
var nextDB = request.result;
if (!nextDB.objectStoreNames.contains('account')) {
nextDB.createObjectStore('account', {keyPath: "id", autoIncrement: true});
}
dbversion += 1;
localStorage.setItem("dbversion", dbversion);
needUpgrade = true;
console.log("indexedDB: upgrade finished");
}
request.onsuccess = function(event){
if (needUpgrade) {
var objectStore = event.target.result.transaction(['account'], "readwrite").objectStore("account");
row = {
'id' : 0,
'username' : dbname,
};
objectStore.add(row);
}
console.log("indexedDB: init");
};
request.oncomplete = function(event){request.result.close();}
}else{
// -- no
localStorage.setItem("dbversion", dbversion);
vCheck.oncomplete = console.log("indexedDB: dbversion unknown (not in localStorage)");
}
}else{
// -- no
console.log("indexedDB: version", dbversion);
console.log("indexedDB: init");
}
}
}
}
function listStores() {
var request = indexedDB.open(dbname, dbversion);
request.onerror = errorHandler;
request.onsuccess = function(event){
var db = request.result;
var allStores = db.objectStoreNames;
console.log(allStores);
}
request.oncomplete = function(event){request.result.close();}
}
function addStore(storeName) {
dbversion = localStorage.getItem("dbversion");
var request = indexedDB.open(dbname, dbversion);
request.onerror = errorHandler;
request.onsuccess = function(event){
var db = request.result;
if (!db.objectStoreNames.contains(storeName)) {
dbversion = parseInt(dbversion) + 1
localStorage.setItem("dbversion", dbversion);
db.close()
var nextRequest = indexedDB.open(dbname, dbversion);
nextRequest.onversionchange = function(ev) {
nextRequest.close();
};
nextRequest.onupgradeneeded = function(event) {
console.log("indexedDB: creating");
var nextDB = nextRequest.result;
nextDB.createObjectStore(storeName, {keyPath: "id", autoIncrement: true});
oStore = storeName;
console.log("indexedDB:", storeName, "created");
}
nextRequest.onerror = errorHandler;
nextRequest.oncomplete = function(event){nextRequest.result.close();}
}else{
oStore = storeName;
console.log("indexedDB:", storeName, "already exists. Do nothing...");
}
}
}
function selectStore(storeName){
oStore = storeName;
console.log("indexedDB: globalVar oStore ==", oStore);
}
function addMember(data) {
var request = indexedDB.open(dbname, dbversion);
request.onerror = errorHandler;
request.onsuccess = function(event){
var db = request.result;
var objectStore = db.transaction([oStore], "readwrite").objectStore(oStore);
row = {
'id' : Date.now(),
'name' : {
'vname' : data['vname'],
'nname' : data['nname'],
},
}
objectStore.add(row);
console.log("indexedDB:", row["id"], "inserted");
}
request.oncomplete = function(event){request.result.close();}
return;
}
function deleteStore(storeName) {
dbversion = localStorage.getItem("dbversion");
dbversion = parseInt(dbversion) + 1
localStorage.setItem("dbversion", dbversion);
var request = indexedDB.open(dbname, dbversion);
request.onerror = errorHandler;
request.onupgradeneeded = function(event){
var db = request.result;
db.deleteObjectStore(storeName);
console.log("indexedDB:", storeName, "deleted");
}
request.oncomplete = function(event){request.result.close();}
}
function errorHandler(event) {
console.log("indexedDB: operation went wrong:");
console.log("indexedDB:", event);
return;
}

调用此函数顺序

listStores()
addStore('TestStore')
selectStore('TestStore')
addMember({'vname':'John', 'nname':'Doe'})
deleteStore('TestStore')
listStores() // <<<<<<<<<<<< hangs up !

编辑:

正如约书亚原来关闭连接的地方是错误的。此外,还有一个非常重要的事实:

在快速删除对象存储之前,您必须先清除它!

这是正确的删除存储()

function deleteStore(storeName) {
// First: Clear the store
var request1 = indexedDB.open(dbname, dbversion);
request1.onsuccess = function(event){
var connection = event.target.result;
var objectStore = connection.transaction([storeName], "readwrite").objectStore(storeName);
var result_clear = objectStore.clear();
result_clear.onerror = errorHandler;
result_clear.onsuccess = function(event){
console.log("indexedDB: clearing Store...");
// Second: Delete the store
dbversion += 1;
localStorage.setItem("dbversion", dbversion);
var request2 = indexedDB.open(dbname, dbversion);
request2.onsuccess = function(event){
var connection2 = event.target.result;
// ---> Garbage Collection
connection2.onversionchange = function(event) {
connection2.close();
};
}
request2.onerror = errorHandler;
request2.onupgradeneeded = function(event){
var connection2 = event.target.result;
connection2.deleteObjectStore(storeName);
console.log("indexedDB:", storeName, "deleted");
}
}
// ---> Garbage Collection
connection.onversionchange = function(event) {
connection.close();
};
}
request1.onerror = errorHandler;
request1.oncomplete = function(e){
}
}

确保您正在监视针对连接而不是打开的请求触发的versionchange事件。

var openRequest = indexedDB.open(name, version);
openRequest.onblocked = function(e) {
// Another connection is open, preventing the upgrade,
// and it didn't close immediately.
};
openRequest.onerror = function(e) {
// Open failed - possibly the version is higher than requested.
};
openRequest.onupgradeneeded = function(e) {
// Check the current version, and upgrade as needed.
var connection = openRequest.result;
if (e.oldVersion < 1) {
// db is new - create v1 schema
}
if (e.oldVersion < 2) {
// upgrade v1 to v2 schema
}
if (e.oldVersion < 3) {
// upgrade v2 to v3, etc
}
};
openRequest.onsuccess = function(e) {
var connection = openRequest.result;
connection.onversionchange = function(e) {
// Close immediately to allow the upgrade requested by another
// instance to proceed.
connection.close();
};
// The connection is open - use it for stuff.
};

上面还演示了通常的版本控制模式 - 您的代码在打开时请求特定版本,并在需要时升级旧架构。当应用程序需要新存储时,可以增加版本号,并在 upgradeneed 处理程序中引入其他步骤。

相关内容

最新更新