2012-10-22 69 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