未在全局作用域声明变量致IndexedDB报错:db未定义
IndexedDB修改条目时db变量未定义问题修复
问题描述
要实现通过输入框填写值,提交修改IndexedDB中已有条目,且后续可检索再次编辑的功能,但运行时报错:Uncaught TypeError: db is undefined。点击按钮触发$('#edit-button').click函数,该函数调用updateMarma,而updateMarma依赖getObjectStore函数,后者需要已声明的db变量。
最初将所有代码放在open.onsuccess = function() {}内时db可正常访问,但为了让函数能独立调用移到外部后,无法正确声明和维护db变量。尝试在open.onupgradeneeded内赋值db = open.result;以及使用IIFE都未解决问题。
问题根源
- 局部变量覆盖外层变量:在
open.onsuccess回调中使用var db = open.result;重新声明了局部db变量,导致外层IIFE中声明的db始终未被赋值,一直处于undefined状态。 - 数据库过早关闭:初始化数据完成后调用
db.close()关闭了数据库连接,后续操作时db已失效。 - 事务与存储对象管理不当:
updateMarma中尝试复用store变量,不符合IndexedDB事务的生命周期规则,应该每次操作都创建新的事务。
修改后的完整代码
(function() { var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB || window.shimIndexedDB; var db; // 外层的db变量,供所有函数访问 // 打开(或创建)数据库 var open = indexedDB.open("marmaDB", 1); console.log("打开数据库..."); // 创建数据库 schema console.log("创建数据库结构..."); open.onupgradeneeded = function(e) { db = e.target.result; // 给外层db赋值 var store = db.createObjectStore("marmasStore", {keyPath: "id"}); store.createIndex("NameIndex", ["name.last", "name.first"]); store.createIndex('sanskrit', 'sanskrit', { unique: false }); store.createIndex('name', 'name', { unique: false }); store.createIndex('marmaGrp', 'marmaGrp', { unique: false }); store.createIndex('location', 'location', { unique: false }); store.createIndex('localisation', 'localisation', { unique: false }); store.createIndex('awareness', 'awareness', { unique: false }); store.createIndex('frequency', 'frequency', { unique: false }); }; // 获取对象存储(事务) function getObjectStore(store_name, mode) { if (!db) { console.error("数据库未连接"); return null; } var tx = db.transaction(store_name, mode); tx.onerror = function(e) { console.error("事务错误:", e.target.error); }; return tx.objectStore(store_name); } // 数据库打开成功回调 open.onsuccess = function(e) { console.log("数据库打开成功"); db = e.target.result; // 给外层db赋值,覆盖可能的onupgradeneeded中的赋值 // 初始化数据(仅在数据库新建或版本升级时执行,可根据需求调整) var tx = db.transaction("marmasStore", "readwrite"); var store = tx.objectStore("marmasStore"); // 先检查是否已有数据,避免重复初始化 store.count().onsuccess = function(countEvt) { if (countEvt.target.result === 0) { const initialMarmaData = [ { id: "ani_ll", sanskrit: "ani", name: "Ani", marmaGrp: "snayu", location: "linker Oberschenkel", localisation: 0, awareness: 0, frequency: 0 }, { id: "ani_rl", sanskrit: "ani", name: "Ani", marmaGrp: "snayu", location: "rechter Oberschenkel", localisation: 0, awareness: 0, frequency: 0 }, { id: "ani_la", sanskrit: "ani", name: "Ani", marmaGrp: "snayu", location: "linker Arm", localisation: 0, awareness: 0, frequency: 0 }, { id: "ani_ra", sanskrit: "ani", name: "Ani", marmaGrp: "snayu", location: "rechter Arm", localisation: 0, awareness: 0, frequency: 0 }, ]; console.log("初始化数据库数据..."); initialMarmaData.forEach((marma) => { var request = store.put(marma); request.onsuccess = (event) => { console.log(event.target.result + " 数据初始化完成"); }; request.onerror = (event) => { console.error("初始化数据失败:", event.target.error); }; }); } }; tx.oncomplete = function() { console.log("初始化事务完成"); // 不再关闭数据库,保持连接供后续操作使用 }; tx.onerror = function(e) { console.error("初始化事务错误:", e.target.error); }; }; // 数据库打开失败回调 open.onerror = function(e) { console.error("数据库打开失败:", e.target.error); }; // 更新Marma条目 function updateMarma(key) { console.log("更新Marma:", key); var store = getObjectStore("marmasStore", 'readwrite'); if (!store) return; var marmaInfo = store.get(key); marmaInfo.onsuccess = function(evt) { var record = evt.target.result; console.log("找到记录:", record); if (!record) { alert("未找到匹配的记录"); return; } // 获取输入框的新值并更新记录 record.location = $('#bodylocation').val(); record.awareness = parseInt($('#awareness').val(), 10); // 保存更新后的记录 var updateRequest = store.put(record); updateRequest.onsuccess = function() { alert("ID " + record.id + " 更新成功"); console.log("记录更新成功:", record); }; updateRequest.onerror = function(e) { console.error("更新记录失败:", e.target.error); alert("更新失败,请查看控制台日志"); }; }; marmaInfo.onerror = function(e) { console.error("获取记录失败:", e.target.error); alert("获取记录失败,请查看控制台日志"); }; } // 编辑按钮点击事件 $('#edit-button').click(function(evt) { evt.preventDefault(); console.log("触发编辑操作"); var key = $('#marmaID').val().trim(); var new_bodylocation = $('#bodylocation').val().trim(); var new_awareness = $('#awareness').val().trim(); if (!key) { alert("请输入有效的Marma ID"); return; } if (!new_bodylocation || isNaN(new_awareness)) { alert("请填写有效的更新值"); return; } console.log("正在编辑:", key); updateMarma(key); }); })();
关键修改说明
- 正确赋值外层db变量:在
open.onupgradeneeded和open.onsuccess中,直接给外层的db赋值(去掉var),确保所有函数能访问到有效的数据库实例。 - 保留数据库连接:移除初始化后的
db.close(),保持数据库连接打开,供后续编辑操作使用。 - 完善事务与错误处理:为事务和请求添加
onerror回调,便于排查问题;每次更新操作创建新的事务,符合IndexedDB的使用规范。 - 补充更新逻辑:在
updateMarma中加入获取输入框新值、更新记录并保存到数据库的逻辑,完成完整的修改流程。 - 初始化数据判断:添加数据数量检查,避免每次打开数据库都重复初始化数据。
内容的提问来源于stack exchange,提问作者Corbinian
相关产品推荐
相关产品推荐

