2012-10-22 30 views
0

我想第一次尝试indexedDB,试图遵循我在互联网上找到的各种示例。它在某种程度上起作用,但是当我读取数据库时,结果不一致。indexedDB读取不一致性

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; 
}; 

的待办事项存储是从一个例子,我发现:

该数据库是如下创建。这是我有困难的网站商店。

我看了网站存储这样的:

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); 
    }; 
}; 

数据库的更新也成功。

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

显示更新(update_sites)大部分时间都正常工作 - 如果我在sync_sites运行后的几秒钟的短时间间隔内运行它,它只会产生不正确的结果。

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

我在错误控制台中看不到任何错误,无论是update_sites正确运行时还是错误结果时,或者sync_sites。事实上,在运行时错误控制台中完全没有错误或警告。

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

FWIW,这是Firefox 16.0.1。

我做错了什么?

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

是否有其他人看到过这种行为?

感谢, 伊恩

回答

3

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

此外,您应该使用单个事务来存储记录。 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); 
}; 
+0

我明白,当alert('sync done')被调用时,数据库更新没有完成。实际上,由于javascript的特性,我认为商店更新甚至还没有开始。我不明白你使用单个事务来存储记录的观点。 – Ian

+0

当你迭代所有从你的xhr结果返回的网站时,将会调用alert('sync done')。但这并不意味着这些站点被存储,因为所有数据库事务都是异步完成的。 Kyaw之所以只使用一次交易有几个原因。 1.每次打开一个事务都有一定的CPU成本(性能不好)。 2.一次又一次打开同一个对象库的写入事务可能会导致锁定并且事务将不得不等待。 (对性能不利)3.现在可以使用oncomplete回调确定所有插入操作已完成。 –

+0

哦!感谢Kristof和Kyaw--现在我明白了!这是一个很好的观点。我做的更新速度很慢。但是,尽管我在很多方面都做得很差,但我仍然不明白为什么它会导致错误的阅读结果,而不仅仅是糟糕的表现。 – Ian