在我的应用中,用户应该能够动态创建和删除objectStores 。感谢indexedDB,这个操作(为什么在世界上)只允许在 onupgradeneeded 中。
触发 onupgradedneeded 后,indexedDB永远不会完成此请求,并且gc永远不会收集此连接。
在现有数据库中创建和删除存储时只存在问题。开头的 onupdateneeded (创建db并创建第一个商店)从未出现任何问题。
我尝试在升级之前关闭每个数据库连接,因为2013年有一个针对Chromium的错误报告,其中提到了这个问题(标记为已修复:https://bugs.chromium.org/p/chromium/issues/detail?id=242115)。
事实上,我没有找到关于这个问题的任何实际信息,这让我想到我在我的代码中做错了...... 但是为什么有些浏览器只是做他们的工作?
这是我重现此错误的代码:
// 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 !
当约书亚结束时,关闭连接的地方是错误的。此外还有一个非常重要的事实:
在您快速删除objectStore之前,您必须先清除它!
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){
}
}
答案 0 :(得分:1)
确保您正在查看针对该连接触发的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.
};
上面还演示了版本控制的常用模式 - 您的代码在打开时请求特定版本,并在需要时升级旧架构。当您的应用程序需要新商店时,您可以增加版本号并在升级所需的处理程序中引入一个额外的步骤。