基本概念
IndexedDB是html5中新增的本地存储数据库,说到数据库,就要区分其是哪种类型,关系型数据库还是非关系型数据库?
常见的Mysql、Oracle都是关系型数据库,而Redis、MongoDB都是非关系型数据;IndexedDB就是一个非关系型数据库;同时IndexedDB也是一个事务型数据库,使用IndexedDB,你可打开一个事务(transaction),在这个事务中完成对数据的修改。和大多数web存储解决方案相同,indexedDB也遵从同源协议(same-origin policy)。 所以你只能访问同域中存储的数据,而不能访问其他域的。
使用IndexedDB,你可以存储或者获取数据,使用一个key索引的。 你可以在事务(transaction)中完成对数据的修改。和大多数web存储解决方案相同,indexedDB也遵从同源协议(same-origin policy). 所以你只能访问同域中存储的数据,而不能访问其他域的。
为何存在?
前端本地存储已经有cookie和webStorage了,那IndexedDB存在的意义是什么?首先我觉得IndexedDB是html5用来替代webSql的;然后cookie存储的数据量非常小,同时每次发送和接受http请求都会携带cookie,如果是非必要的请求信息就导致浪费带宽。webStorage突破了cookie仅有4k大小的限制,其使用key-value的形式存储数据,value值仅仅支持string,当你需要存储一个对象时,就需要JSON.Stringify和JSON.parse对该对象处理。由此就导致了webStorage不适合大量的结构化的数据存储。由此就诞生了IndexedDB。
如何使用?
1.打开或创建一个数据库
const request = indexedDB.open('dataBaseTest', 1);
request.onsuccess = function() {
console.log('打开成功!')
}
request.onerror = function() {
console.error('打开失败!')
}
open方法打开一个数据库,第一个参数是打开(创建)的数据库名称,第二个参数是数据库版本号,默认为1。如果该数据库在当前域不存在,则创建数据库,如果存在则打开;
这时候我们console出request:
我们看到request并不会打开数据库或者开始一个事务。而我们需要的东西都会后续的result对象中获得;
2.创建一个Store
// 第一次创建数据库或者更新数据库
request.onupgradeneeded = function(e) {
console.log('create || update')
const db = this.result;
if(!db.objectStoreNames.contains('student')){
const store = db.createObjectStore('student', {
keyPath: 'id',
autoIncrement: true
});
store.createIndex("name", "name", {
unique: false
});
store.createIndex("score", "score", {
unique: false
});
}
}
在onupgradeneeded函数中创建一个store。该函数仅在首次创建数据库,或者该数据库版本更新时调用。
this.result包含了这个数据库的所有信息。同时,createObjectStore只能在onupgradeneeded调用。
上面的代码中,我们创建了一个名为student的store,store的概念类似一个表。同时我们添加一个id字段为key,还添加name和score字段;这时候我们打开浏览器开发者工具查看Application:
准备工作就此就绪了
3.开打一个事务,获取一个store,并对该store做增删改查操作
由于每个事务都要在当前数据库中操作,所以我们修改上面的onsuccess回调函数,将其result存储在一个全局变量中:
let myDB = null;
const request = indexedDB.open('dataBaseTest', 1);
request.onsuccess = function() {
console.log('打开成功!');
myDB = this.result;
}
request.onerror = function() {
console.error('打开失败!')
}
后续操作都可以在这个myDB中进行;
1. 添加一条数据 (body中添加了一个#addBtn的按钮)
document.getElementById('addBtn').onclick = addData;
function addData() {
// 打开一个事务,使用‘student’ object store,以读写模式
const transaction = myDB.transaction('student', 'readwrite')
// 获取student object Store
const myStore = transaction.objectStore('student');
const resadd = myStore.add({
'name': 'tongban',
'score': 95
});
resadd.onsuccess = function(){
console.log("添加成功!");
}
resadd.onerror = function(e){
console.error(e.target.error);
}
}
transaction方法接受三个参数(后两个是可选的)并返回一个事务对象。
第一个参数是事务希望跨越的对象存储空间的列表。如果你只需要一个对象存储空间时,你只需要传该对象名的字符串;多个的话就需要以数组的形式传入了。如果你想获得所有对象存储空间,你可以传入一个空数组;第二个参数默认是”readonly”,这里我想要插入一条数据,所以我们设为”readwrite”;
现在我们已经有了一个事务,我们需要理解它的生命周期。事务和事件循环的联系非常密切。如果你创建了一个事务但是并没有使用它就返回给事件循环,那么事务将变得无效。保持事务活跃的唯一方法就是在其上构建一个请求。当请求完成时你将会得到一个 DOM 事件
修改插入值,多次操作后,查看Application:
2.修改一条数据
put:其和add的用法相同,当id已存在时则修改该条数据,不存在时则相当于add的作用;
3.删除一条数据
const myStore = myDB.transaction('student', 'readwrite').objectStore('student');
const resDel = myStore.delete(1);
resDel.onsuccess = function() {
console.log('删除成功')
}
删除后的Application:
4.获取一条数据
const myStore = myDB.transaction('student', 'readwrite').objectStore('student');
const resGet = myStore.get(3);
resGet.onsuccess = function() {
console.log(this.result) // {name: "technical", score: 88, id: 3}
}
5.游标(openCursor)
使用 get() 要求你知道你想要检索哪一个键。如果你想要遍历对象存储空间中的所有值,那么你可以使用游标。由此你可以通过特定的字段对该条数据做操作:
const myStore = myDB.transaction('student', 'readwrite').objectStore('student');
myStore.openCursor().onsuccess = function(event) {
const cursor = event.target.result;
if (cursor) {
console.log(cursor.value);
// 如果你想要继续,则调用continue
cursor.continue();
}
}
控制台输出:
注:本文仅对indexedDB做简单介绍,详细信息及api请访问MDN。