IndexedDB遍历关联表数据上传服务器时出现数据重复该如何解决
问题原因
- 变量作用域冲突:你在全局定义了
syncFormData,同时在SyncData的循环里又定义了同名局部变量,但getTable2、getTable3中访问的是全局的syncFormData。多个TableA行的异步处理流程并行执行,都会往同一个全局FormData里追加数据,导致前一次的残留数据被带到后一次的提交中,出现重复。 - 数组取值错误:
Array.filter()返回的是符合条件的数组,你直接用tblbData.Column1、tblbData.TableBId实际上取的是数组的属性,值为undefined,当关联多条数据时只会处理第一条甚至完全无法正确取值,变量混乱进一步加剧重复。 - 异步时序混乱:
$.each是同步执行的,会一次性触发所有TableA行的getTable2调用,但IndexedDB的读取是异步操作,回调触发顺序和循环顺序不一致,不同数据行的关联数据被交叉写入全局FormData,提交时混杂了多组数据。 - 关联数据未遍历:TableB和TableC是一对多关系,你拿到过滤后的结果后没有循环遍历所有匹配行,只处理了第一条数据,遗漏的同时也会导致后续提交时残留之前的数据。
修复方案
核心思路是改用Promise+async/await控制异步时序,每个TableA行对应独立的FormData实例,避免数据交叉,同时遍历处理所有关联的子表数据。
- 改造IndexedDB取数方法为Promise风格,方便异步流程控制:
function getIndexeDbData(storeName) { return new Promise((resolve, reject) => { const myDB = window.indexedDB.open(dbName); myDB.onsuccess = function () { try { if (this.result.objectStoreNames.contains(storeName)) { this.result.transaction(storeName).objectStore(storeName).getAll().onsuccess = function (event) { resolve(event.target.result); }; } else { resolve(false); } } catch (ex) { reject(ex); } }; myDB.onerror = reject; }) }
- 重写同步逻辑,废弃全局FormData,按组处理关联数据:
async function SyncData() { const tableAData = await getIndexeDbData("TableA"); if (!tableAData) return; // 按顺序逐行处理TableA数据,避免并行混乱 for (const tblAData of tableAData) { // 每个TableA行对应独立的FormData,互不干扰 const syncFormData = new FormData(); syncFormData.append('TableA.Column1', tblAData.Column1); syncFormData.append('TableA.Column2', tblAData.Column2); // 组装当前TableA关联的所有子表数据 await processTableB(tblAData.TableAId, syncFormData); // 单组数据组装完成后再提交 await postToDb(syncFormData); } } async function processTableB(tableAId, syncFormData) { const allTableB = await getIndexeDbData("TableB"); if (!allTableB) return; // 遍历当前TableA关联的所有TableB行 const matchedTableB = allTableB.filter(x => x.TableAId === tableAId); for (const tblbData of matchedTableB) { syncFormData.append('TableB.Column1', tblbData.Column1); syncFormData.append('TableB.Column2', tblbData.Column2); // 组装当前TableB关联的TableC数据 await processTableC(tblbData.TableBId, syncFormData); } } async function processTableC(tableBId, syncFormData) { const allTableC = await getIndexeDbData("TableC"); if (!allTableC) return; // 遍历当前TableB关联的所有TableC行 const matchedTableC = allTableC.filter(x => x.TableBId === tableBId); for (const tblCData of matchedTableC) { syncFormData.append('TableC.Column1', tblCData.Column1); syncFormData.append('TableC.Column2', tblCData.Column2); } } // 改造提交方法,接收FormData参数并返回Promise function postToDb(syncFormData) { return new Promise((resolve, reject) => { $.ajax({ url: '你的服务端提交接口地址', type: 'POST', data: syncFormData, processData: false, contentType: false, success: resolve, error: reject }) }) }
- 可选优化:如果数据量较大,可以给TableB的
TableAId、TableC的TableBId建立IndexedDB索引,直接用索引查询对应数据,不需要每次全表扫描过滤,能大幅提升查询效率。
内容的提问来源于stack exchange,提问作者Developer
相关产品推荐
相关产品推荐

