indexedDB读取不一致

时间:2012-10-22 20:57:44

标签: javascript html5 indexeddb

我第一次尝试使用indexedDB,尝试按照我在Internet上找到的各种示例。它有点起作用,但是当我读取数据库时,我得到的结果不一致。

数据库创建如下:

myapp.indexedDB.open = function() {
    var request = indexedDB.open('todos', "2");

    request.onblocked = function(e) {
        alert('Please close all other tabs with this site open so the database can be updated.');
    };

    request.onsuccess = function(e) {
        myapp.indexedDB.db = e.target.result;
        myapp.indexedDB.db.onversionchange = function(e) {
            myapp.indexedDB.db.close();
            alert('The database is being upgraded. Please reload.');
        };
        myapp.indexedDB.getAllTodoItems();
    };

    request.onupgradeneeded = function(e) {
        var db = e.target.result;

        if(!db.objectStoreNames.contains('todo')) {
            var store = e.currentTarget.result.createObjectStore(
                'todo',
                {keyPath: "timeStamp"}
            );
        }

        if(!db.objectStoreNames.contains('sites')) {
            var site_store = e.currentTarget.result.createObjectStore(
                'sites',
                {keyPath: 'id'}
            );
        }
    };
    request.onfailure = myapp.indexedDB.onerror;
};

todo商店来自我发现的一个例子。这是我遇到困难的网站商店。

我像这样阅读网站商店:

function update_sites() {
    $('#sites_table').ig_grid('delete_all_rows');
    var db = myapp.indexedDB.db;
    var trans = db.transaction(["sites"], "readwrite");
    var store = trans.objectStore('sites');

    var cursorRequest = store.openCursor();

    cursorRequest.onsuccess = function(e) {
        var result = e.target.result;
        if(!!result == false) return;

        render_site(result.value);
        console.log('rendered a site');
        result.continue();
    };

    cursorRequest.onerror = myapp.indexedDB.onerror;
}

function render_site(site) {
    $('#sites_table').ig_grid('add_row', [site.id,site.id,site.flag,site.site_code,site.site_name,site.owner_name,site.address,site.hive_capacity,site.hive_count,render_status(site.status_id)]);
}

到目前为止,一切都很顺利。写入数据库的数据将被正确读取和呈现。

更新数据库时出现问题。更新完成如下:

function sync_sites() {
    display_status('');
    var jqxhr = $.ajax({
        type:   "GET",
        url:    '/myapp.pl/REST/sites'
    })
    .fail(function(jqXHR, textStatus) {
        display_status(jqXHR.responseText);
    })
    .done(function(data, textStatus, jqXHR) {
        var sites = jQuery.parseJSON(data.data);
        for (var i = 0; i < sites.length; i++) {
            myapp.indexedDB.add_site(sites[i]);
        }
        alert('sync done');
    });
}

myapp.indexedDB.add_site = function(site) {
    var db = myapp.indexedDB.db;
    var trans = db.transaction(["sites"], "readwrite");
    var store = trans.objectStore('sites');
    var request = store.put(site);

    request.onsuccess = function(e) {
        // TODO: whatever is appropriate if the site is added successfully
    };

    request.onerror = function(e) {
        console.log(e.value);
    };
};

数据库的更新也会成功。

问题是数据库更新开始后不久 - 在显示'sync done'警告之后,update_sites函数清空显示的站点表并且不添加任何站点:就像数据库是空的一样。然后,如果我继续重新加载站点显示,在几秒钟(几次重新加载)之后,几百到几千行被添加到站点表中,每行重复几次。通常情况下,网站商店/表中有216条记录。最后,关于上次数据库更新(put)完成的时间(我认为),显示更新再次正常工作。

显示更新(update_sites)在大多数情况下都能正常工作 - 如果我在sync_sites运行后的几秒钟的短暂间隔内运行它,它只会得到不正确的结果。

有两种错误模式:第一种,没有数据从商店读取,就好像它是空的或光标没有匹配的记录(从未成功);并且在第二个游标中,当游戏中的所有记录都被返回后,游标不会停止,它会一遍又一遍地循环遍历所有记录,直到最终在一些看似任意的点停止。

我在错误控制台中看不到任何错误,无论是在update_sites正确运行时还是在提供不正确的结果时,还是在sync_sites中。事实上,当它运行时,错误控制台中根本没有错误或警告。

我已经使用sqlite3检查了底层数据库,并且我可以看到数据库中没有重复的记录。 object_data中有219条记录:3条与todo商店相关,216条与网站商店相关。

FWIW,这是Firefox 16.0.1。

我做错了吗?

我是否可以启用其他可能有助于查明错误原因的错误,警告,跟踪或诊断?

还有其他人看到过这种行为吗?

谢谢, 伊恩

1 个答案:

答案 0 :(得分:3)

由于IndexedAPI alert('sync done');的异步性质不正确,因为IDBRequest onsuccess处理程序并不意味着它已成功添加。只有IDBTransaction的oncompeleted处理程序才能确保它已添加并准备好查询记录。

此外,您应该使用单个事务来存储记录。 myapp.indexedDB.add_site应为myapp.indexedDB.add_sites(sites, callback),以便循环播放记录。当oncompeleted它调用回调时。

编辑:添加add_sites功能。

myapp.indexedDB.add_sites = function(sites, callback) {
  var db = myapp.indexedDB.db;
  var trans = db.transaction(["sites"], "readwrite");
  trans.oncompleted = callback;
  var store = trans.objectStore('sites');

  var put = function(i) {
    var request = store.put(sites[i]);

    request.onsuccess = function(e) {
      i--;
      if (i >= 0) put(i);    
    };

    request.onerror = function(e) {
      console.log(e.value);
    };
  };

  put(sites.length - 1);
};