在大部分前端业务场景下,往往cookie,sessionStorage,localStorage等存储方案就能处理大部分问题。但是随着前端出于业务的复杂程度提升以及更多的解决方案需求,前端就需要一种能够存储大量数据的方案。
于是浏览器推出了2种方案:关系型数据库webSQL和非关系型数据库indexedDB
由于W3C的规定,导致WebSQL没有称为规范,所以支持性并不是很好。而indexedDB则不同,其天生就是JS的数据结构,所以更加适合作为前端的存储方案。
indexedDB的支持情况
首先作为前端,对数据库还是有些陌生的,特别的非关系型数据库。所以还是有必要先了解下概念。
概念
- 数据库(database):一个页面下可以建立多个数据库,数据库名name+版本号version
- 对象仓库(object store):对应的就是关系型数据库中的表,但是存储方式完全不同
- 事务(transaction):对数据进行持久性和原子性的操作(读写、只读和版本变更)
- 索引(index):能更快搜索到对应绑定的数据对象,类似于书本的目录页面引导
小贴士:索引不是主键,是另一种关联,便于搜索任意字段
接着就是indexedDB的一些特性
- key-value存储
- 事务模式:所有操作都必须在事务中进行,如果出错就会回滚
- 异步操作
- 以DOM事件回调
- 同源策略限制
- 支持Blob,File等多种复杂数据类型
那么直接正如主题
创建数据库
// 使用open来创建一个新的数据库(默认版本为1)或者更新一个更高版本的现有数据库,注意,版本号不能为浮点数
var request = window.indexedDB.open("MyTestDatabase");
var request = window.indexedDB.open("MyTestDatabase", 3);
一个indexedDB数据库就被创建完成了。更新版本,点击Refresh database就可以发现Version变成了3
onupgradeneeded:该方法会在数据库版本变化的时候被调用(新建也会)
request.onupgradeneeded = function(event) {
// 拿到数据库的实例
var db = event.target.result;
console.log(db)
}
可以在这里对数据库进行结构定义,比如创建对象仓库,构建仓库的结构等等
const request = window.indexedDB.open("MyTestDatabase", 3)
request.onupgradeneeded = function(event) {
const db = event.target.result;
// 创建一个person的对象仓库,并且设置主键为id,autoIncrement是指定主键是否需要是一个递增的整数
const objectStore = db.createObjectStore('person', { keyPath: 'id', autoIncrement: true })
// 新建索引,参数分别为:索引名称,索引所在的属性,配置 如unique表示是否可以使用unique索引,true表示可以使用,即表示不存在重复
objectStore.createIndex('name', 'name', { unique: false })
}
对整个数据库实例不同状态的监听
// 冒泡机制,接受所有的报错信息,错误会中断当前处理事务,如果不做一些错误拦截,比如stopPropagation阻止冒泡,那么事务就会回滚
request.onerror = function (event) {
console.error("Database error: " + event.target.errorCode)
};
request.onsuccess = function (event) {
db = event.target.result;
}
增删改查
- objStore.add()
- objectStore.delete()
- objectStore.put()
- objectStore.get()
所有对对象仓库操作的行为都必须依赖于事务
transaction方法来开启一个事务,并想对象仓库中添加数据
// ...
选择一个数据库,并且选择事务类型(readnoly(默认),readwrite,versionchange )
var customerObjectStore = db.transaction("person", "readwrite");
// objectStore方法选择对象仓库
var objectRepository = customerObjectStore.objectStore("person");
// 添加对应数据,这里注意,除非设定了keyPath字段(不是自动递增)就必须要有该属性,别的都是自定义的
objectRepository.add({ name: 'a' });
objectRepository.add({ name: 'b', age: 22 })
//...
读取数据,参数为主键
var request = objectRepository.get(1);
利用索引查询
var index = objectRepository.index('name');
console.log("index: ", index)
var request = index.get('a');
console.log("request: ", request)
使用游标全局查找对应的值
objectStore.openCursor().onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
alert("Name for name " + cursor.key + " is " + cursor.value.name);
cursor.continue();
}
else {
alert("No more entries!");
}
};
修改
objectRepository.put({ id: 1, name: 'c', age: 35 });
删除
objectRepository.delete(2)
获取对象仓库中的所有数据
getAll方法可以获取所有数据
function getAllState() {
const objectStore = getObjectStore('person')
var allRecords = objectStore.getAll();
allRecords.onsuccess = function() {
console.log(allRecords.result);
};
}