为了实现客户端缓存,虽然已经有很多技术被不断推出和应用,但是随着浏览器功能的不断增强和完善,现有的缓存技术,其局限性也变得越来越明显:
这些就是 IndexedDB(Indexed DataBase)诞生的背景,从字面上可以看出,这就是浏览器提供的本地数据库。IndexedDB可以被网页脚本创建和操作。IndexedDB 允许储存大量数据,提供查找接口,还能建立索引。这些都是 Web Storage 所不具备的。
// 创建或打开数据库 const myDB = window.indexedDB.open('myDB', 1); // 数据库连接成功 myDB.addEventListener('success', e => { console.log("数据库连接成功~"); }); // 数据库连接失败 myDB.addEventListener('error', e => { console.log("数据库连接失败~"); });
对象仓库(Object Store)是 indexedDB 数据库的基础,熟悉数据库的朋友都知道数据库表的含义,这个对象仓库(以下统一简称仓库)其实就类似于数据库中表的概念。
const myDB = indexedDB.open('myDB', 2); myDB.addEventListener('upgradeneeded', e => { const dbResult = e.target.result; // 创建一个"用户信息"仓库 UserInfo const createdStore = dbResult.createObjectStore( 'UserInfo', { keyPath: 'id', autoIncrement: false } ); });
原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。(原子性的意思是每次操作都可以是最小单元,即是可回退也可执行)
一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。
隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中。
const myDB = indexedDB.open('myDB', 3); myDB.addEventListener('success', e => { const dbResult = e.target.result; const dbTrans = dbResult.transaction('UserInfo', 'readwrite'); });
在数据操作前首先是获取事务对象,通过事务对象的objectStore()方法获取具体的仓库
// 打开数据库,获取dbResult对象 // ... // 创建事务 const dbTrans = dbResult.transaction(['UserInfo'], 'readwrite'); // 获取仓库 const dbStore = dbTrans.objectStore('UserInfo'); // 后续其他操作 // ...
// 使用add()方法,参数为一条数据对象 const dbRequest = dbStore.add({ id: 1, name: '张三', age: 20, email: 'zhangsan@example.com' }); dbRequest.onsuccess = e => { console.log('数据添加成功~'); }; dbRequest.onerror = e => { console.log('数据添加失败~'); };
// 使用get()方法,参数为主键的值,即示例中id==1的数据 const dbRequest = dbStore.get(1); dbRequest.onsuccess = e => { const { result } = dbRequest; if (result) { const { name, age, email } = result; console.log('name:', name); console.log('age:', age); console.log('email:', email); } else { console.log('未查到对应数据'); } }; dbRequest.onerror = e => { console.log('数据查询失败~'); };
const myDB = indexedDB.open('myDB', 4); myDB.addEventListener('success', e => { const dbResult = e.target.result; const dbTrans = dbResult.transaction('UserInfo'); const dbStore = dbTrans.objectStore('UserInfo'); const boundRange = IDBKeyRange.bound(1,5); const dbRequest = dbStore.openCursor(boundRange, 'next'); dbRequest.onsuccess = e => { const dbCursor = dbRequest.result || e.target.result; if (dbCursor){ const { key, value } = dbCursor; console.log('id:', key); console.log('name:', value.name); console.log('age:', value.age); console.log('email:', value.email); dbCursor.continue(); } else { console.log('编辑完毕~'); } }; });
// 使用delete()方法,参数为主键的值 const dbRequest = dbStore.delete(1); dbRequest.onsuccess = e => { console.log('数据删除成功~'); }; dbRequest.onerror = e => { console.log('数据删除失败~'); };
// 使用put()方法,参数为一条数据对象 const dbRequest = dbStore.put({ id: 1, name: '李四', age: 22, email: 'lisi@example.com' }); dbRequest.onsuccess = e => { console.log('数据更新成功~'); }; dbRequest.onerror = e => { console.log('数据更新失败~'); };
const myDB = indexedDB.open('myDB', 5); myDB.addEventListener('upgradeneeded', e => { const dbResult = e.target.result; // 创建一个"用户信息"仓库 UserInfo const createdStore = dbResult.createObjectStore( 'UserInfo', { keyPath: 'id', autoIncrement: false } ); // 创建索引,索引值为ageIndex,对应的键名(或称属性)为age createdStore.createIndex( 'ageIndex', 'age', { unique: false } ); });
createIndex(indexName, pathKey, options)方法接收三个参数:
indexName: 要创建的索引名,该值唯一,不可重复
pathKey: 仓库里需要建立索引的目标键名(key),或者多个键名组成的数组
options: 是一个可选的配置参数对象,有unique和multiEntry两个值
unique: 用来指定索引值是否可以重复,为true代表不能相同,为false时代表可以相同
multiEntry: 当第二个参数keyPath为一个数组时,如果multiEntry是true,则会以数组中的每个元素建立一条索引,如果是false,则以整个数组为keyPath值,添加一条索引.
const myDB = indexedDB.open('myDB', 4); myDB.addEventListener('success', e => { const dbResult = e.target.result; const dbTrans = dbResult.transaction('UserInfo'); const dbStore = dbTrans.objectStore('UserInfo'); const lowerBound = IDBKeyRange.lowerBound(20); const indexStore = dbStore.index('ageIndex'); const dbRequest = indexStore.openCursor(lowerBound, 'next'); dbRequest.addEventListener('success', e => { const dbCursor = e.target.result; if (dbCursor) { const { key, value } = dbCursor; console.log('id:', key); console.log('name:', value.name); console.log('age:', value.age); console.log('email:', value.email); dbCursor.continue(); } else { console.log('编辑完毕~'); } }) });