【问题标题】:IndexedDB can make database unreachable (getting blocked), how unblock?IndexedDB 可以使数据库无法访问(被阻塞),如何解除阻塞?
【发布时间】:2013-06-11 01:50:23
【问题描述】:

更新 我发现问题是它被阻止了。尽管数据库总是由同一个扩展创建和升级,但它并没有关闭。所以现在我正在调用“onblocked”函数。

如何“解除阻止”当前被阻止的数据库?将来如何防止这种情况发生?这是一个应用程序,所以没有标签正在使用它。而且由于我无法打开这些数据库甚至删除它们(这也会被阻止),我该如何关闭它们?

(对于任何想知道的人,为了从一开始就避免此问题,您必须执行以下操作:)

mydb.onversionchange = function(event) {
    mydb.close();
};

原帖

如果我(不小心)尝试使用错误的版本打开和升级,IndexedDB 会死掉并且无法打开。据我所知,没有办法向 indexedDB 询问最新版本的数据库。因此,如果我尝试运行以下代码两次,它会破坏数据库并且无法打开:

而且它从不抛出错误或调用 onerror。它只是静静地坐着

var db = null;

//Note, no version passed in, so the second time I do this, it seems to cause an error
var req = indexedDB.open( "test" );
req.onsuccess = function(event) { console.log( "suc: " + event.target.result.version ); db = event.target.result; };
req.onerror = function(event) { console.log( "err: " + event ); };
req.onupgradeneeded = function(event) { console.log( "upg: " + event.target.result.version ); };

//We're doing in interval since waiting for callback
var intv = setInterval(
    function()
    {
        if ( db === null ) return;

        clearInterval( intv );

        var req2 = indexedDB.open( "test", db.version + 1 );
        req2.onsuccess = function(event) { console.log( "suc: " + event.target.result.version ); };
        req2.onerror = function(event) { console.log( "err: " + event ); };
        req2.onupgradeneeded = function(event) { console.log( "upg: " + event.target.result.version ); };
    },
    50
);

所有这些代码都在我的chrome.runtime.onInstalled.addListener 中。所以当我更新我的应用程序时,它会再次调用它。如果我在没有传入新版本的情况下调用indexedDB.open( "test" ),然后再次运行 setInterval 函数,则会导致一切变得不可用,并且我永远无法再次打开“测试”。如果我可以在尝试打开数据库之前查询 indexedDB 的数据库版本,这将得到解决。存在吗?

【问题讨论】:

    标签: google-chrome google-chrome-extension local-storage indexeddb google-chrome-app


    【解决方案1】:

    也许这有帮助?

    function getVersion(callback) {
      var r = indexedDB.open('asdf');
      r.onblocked = r.onerror = console.error;
      r.onsuccess = function(event) {
        event.target.result.close();
        callback(event.target.result.version);      
      };
    }
    
    getVersion(function(version) {
      console.log('The version is: %s', version);
    });
    

    好的,根据 convo,这个小 util 函数可能会让你走上正轨:

    var DATABASE_NAME_CONSTANT = 'whatever';
    
    // Basic indexedDB connection helper
    // @param callback the action to perform with the open connection
    // @param version the version of the database to open or upgrade to
    // @param upgradeNeeded the callback if the db should be upgraded
    function connect(callback, version, upgradeNeeded) {
       var r = indexedDB.open(DATABASE_NAME_CONSTANT, version);
       if(upgradeNeeded) r.onupgradeneeded = updateNeeded;
       r.onblocked = r.onerror = console.error;
       r.onsuccess = function(event) {
         console.log('Connected to %s version %s', 
           DATABASE_NAME_CONSTANT, version);
         callback(event.target.result);
       };
    }
    
    // Now let us say you needed to connect
    // and need to have the version be upgraded
    // and need to send in custom upgrades based on some ajax call
    
    function fetch() {
      var xhr = new XMLHttpRequest();
      // ... setup the request and what not
      xhr.onload = function(event) {
        // if response is 200 etc
        // store the json in some variable
        var responseJSON = ...;
    
        console.log('Fetched the json file successfully');
        // Let's suppose you send in version and updgradeNeeded
        // as properties of your fetched JSON object
        var targetVersion = responseJSON.idb.targetVersion;
        var upgradeNeeded = responseJSON.idb.upgradeNeeded;
    
        // Now connect and do whatever
        connect(function(db) {
          // Do stuff with the locally scoped db variable
          // For example, grab a prop from the fetched object
          db.objectStore('asdf').put(responseJSON.recordToInsert);
    
          // If you feel the need, but should not, close the db
          db.close();
          console.log('Finished doing idb stuff');
        }, targetVersion, upgradeNeeded);
      }
    }
    

    【讨论】:

    • 它从不调用onsuccess。它只调用onblocked,并在其中导致错误:DOM IDBDatabase Exception 11
    • 试图澄清一下,即使您没有将版本参数传递给 indexedDB.open,上面也会将“阻塞”错误打印到控制台?
    • 另外,查看stackoverflow.com/questions/11898375/…。它可能会帮助你。避免使用全局 db 变量。只能从回调中访问。这可能会解决您的阻塞问题。 indexedDB 的设计者使用回调模式来允许异步函数调用,所以尝试使用全局 db 变量只会让你头疼。
    • 对你的第一个问题:是的,即使没有版本参数,它也会抛出错误。
    • 对于您的第二个想法,这是一个想法。我在 IndexedDB 上阅读的所有内容(所有教程和介绍)都建议保存对数据库的引用。您发布的链接显示错误是因为全局数据库为空,但在我的情况下不会发生这种情况,因为我在调用更新函数之前会在一段时间内检查它。如果我有一个有效的db,我只会更新。将db 保存到全局变量的原因是有时indexedDB.open(..) 调用可能需要1 多秒才能调用onsuccess 回调。
    【解决方案2】:

    我认为最好总是提供版本号。如果您不这样做,您将如何管理数据库结构的升级?如果你不是一个很好的机会,你会遇到客户端上相同的数据库版本将具有其他数据库结构的情况,我认为这不是你想要的。所以我建议将版本号保存在一个变量中。

    此外,在使用 indexeddb 时,您必须提供从所有以前版本到当前版本的升级计划。这意味着版本 4 具有一定的结构,但您必须能够从头开始获得与版本 1,2 和 3 相同的结构

    【讨论】:

    • 您如何建议在 chrome 重启时保存该版本号?
    • 是的,但 chrome 不会在重新启动时保存它。想象一下,我的应用程序可以连接到服务器以检查新数据和数据模式的更改(通过 ajax)。如果发现,它将更改架构并更新版本。将该信息保存到 javascript 中的变量中(我认为)不会在 chrome 重新启动时存在。会吗?
    • 如果是这种情况,我建议您跟踪所有打开的连接,以便关闭它们。或者每次操作完成时关闭连接。这就是我构建我的 lib linq2indexeddb 的方式
    • 如果你调用db.close() 是否需要再次调用异步db.open() 来运行任何输血? (我认为确实如此,但想确定一下)
    • 不,它没有,您可以在交易完成时调用它。 txn.oncomplete = function (e){ e.target.close();}
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-16
    • 2019-11-08
    • 2016-06-17
    • 2016-03-31
    • 2014-12-22
    • 1970-01-01
    相关资源
    最近更新 更多