浏览器的本地存储,一般有Cookie,LocalStorage,webSQL; Cookie 与 LocalStorage 一般用于小数据量的存储,webSQL现阶段已经废弃;现在浏览器本地存储大量数据一般都是用indexedDB数据库;就数据库类型而言,IndexedDB 不属于关系型数据库(不支持 SQL 查询语句),更接近 NoSQL 数据库。
1.判断浏览器是否支持 indexedDB
window.indexedDB用于判断当前浏览器是否至此 indexedDB ,返回 IDBFactory 对象
if(window.indexedDB){
//支持
}else{
//不支持
}
2.打开/新建数据库
window.indexedDB.open(name,vision);
open方法支持打开一个本地数据库
参数:
name: 表示你要打开数据库的名称,不可省略
vision: 表示你打开数据库的版本,可省略
注:
① 当打开数据库时,这个数据库不存在,会自动新建再打开,如果存在,则直接打开。
② vision版本号不能低于当前存在的数据库的版本,否则打开数据库会失败。
③ vision版本号只能是整数
IndexedDB 所有操作都是异步的,防止在操作IndexedDB时,浏览器锁死;open在打开数据库的时候,会产生回调函数;
success:打开成功。
error:打开失败。
upgradeneeded:第一次打开该数据库,或者数据库版本发生变化。
blocked:上一次的数据库连接还未关闭。
第一次打开数据库时,会先触发upgradeneeded事件,然后触发success事件。
var req=window.indexedDB.open("db",1);
req.onupgradeneeded=function(){
//第一次打开
}
req.onsuccess=function(){
// 成功
};
req.onerror=function(){
// 失败
};
req.onblocked=function(){
// 连接未关闭
};
如果同时 open 一个数据库,但是版本号不一样,最终生成的数据库会以高版本进行显示
// 同时打开同一个数据库 但是版本号不一致
window.indexedDB.open("demoIndexDB",2);
window.indexedDB.open("demoIndexDB",3);
最终生成的数据库版本为:3
3.indexedDB实例对象的方法
open函数的回调函数接受一个事件对象event作为参数,它的target.result属性就指向打开的IndexedDB数据库。
req.onupgradeneeded=function(e){
var db=e.target.result;
}
req.onsuccess=function(){
var db=e.target.result;
};
获得数据库实例以后,就可以用实例对象的方法操作数据库。
4.createObjectStore 创建存储仓库
createObjectStore方法用于创建存放数据的“对象仓库”,相当于一张数据表,参数为名字;如果创建的"对象仓库"已经存在,则会创建失败;
req.onupgradeneeded=function(e){
var db=e.target.result;
//创建一个名字为user的对象仓库
var userObjStore=db.createObjectStore("user");
}
createObjectStore方法还可以接受第二个对象参数,用来设置“对象仓库”的属性。
req.onupgradeneeded=function(e){
var db=e.target.result;
//创建一个名字为user的对象仓库,并将其 id 作为该 对象仓库 的主键
var userObjStore=db.createObjectStore("user",{keyPath:"id"});
}
req.onupgradeneeded=function(e){
var db=e.target.result;
//创建一个名字为user的对象仓库,并添加一条自增的数据作为键
var userObjStore=db.createObjectStore("user",{autoIncrement:true});
}
keyPath:表示所存入对象的id属性用作每条记录的键名(id不能重复),默认值为null,类似于数据表的主键;
autoIncrement:表示,是否使用自动递增的整数作为键名(自增),默认为false。
一般来说,keyPath和autoIncrement属性只要使用一个就够了,如果两个同时使用,表示键名为递增的整数,且对象不得缺少指定属性。
4.objectStoreNames 属性
在使用 createObjectStore 创建一个对象仓库的时候,如果该对象仓库已经存在,则会跑出一个错误,所以一般在创建一个对象仓库之前,需要先进行判断,该对象仓库是否存在;
数据库对象的objectStoreNames属性返回一个DOMStringList对象,里面包含了当前数据库所有“对象仓库”的名称;
使用DOMStringList对象的contains方法,检查数据库中某个“对象仓库”是否存在。这样可以避免重复创建抛出错误。
req.onupgradeneeded=function(e){
var db=e.target.result;
if( ! db.objectStoreNames.contains("user")){
var userObjStore=db.createObjectStore("user",{autoIncrement:true});
}
}
5.transaction 创建数据库事务
在操作数据库中的数据时,必须先创建一个事务;
transaction方法用于创建数据库事务。
两个参数:
①第一个参数:一个数组,里面是所涉及的是需要操作的对象仓库,通常是只有一个;
②第二个参数:一个表示操作类型的字符串。目前,操作类型只有两种:readonly(只读)和readwrite(读写)。添加数据使用readwrite,读取数据使用readonly。
transaction方法返回一个事务对象,该对象的objectStore方法用于获取指定的对象仓库。
req.onsuccess=function(){
var db=e.target.result;
var t=db.transaction(["user"],"readwrite");
var userStore=t.objectStore("uesr");
};
6.objectStore 操作数据库中的数据
①添加数据:add方法
②读取数据:get方法
③更新记录:put方法
④删除记录:delete方法
⑤遍历数据:openCursor方法
- 添加数据
req.onsuccess=function(e){
var db=e.target.result;
var t=db.transaction(["user"],"readwrite");
var store=t.objectStore("user");
var addResult=store.add({
name:"yanwu",
age:25,
pid:1001
});
addResult.onsuccess=function(){
console.log("添加成功");
};
addResult.onerror=function(){
console.log("添加失败");
}
};
*添加数据的操作是异步执行的,需要在回调函数中去判断数据是否添加成功。
- put方法
put方法同add方法的使用方法相同,需要注意的是在put数据时,若存在相同的key,则是更新,若不存在相同的key,则是添加。
- get方法
get方法用于获取数据,在没有建立索引的情况下,只能根据数据的key来获取数据;
req.onsuccess=function(e){
var db=e.target.result;
var t=db.transaction(["user"],"readwrite");
var store=t.objectStore("user");
var getResult=store.get(1);
getResult.onsuccess=function(e){
var data=e.target.result;
console.log(data.name);
console.log(data.age);
console.log(data.pid);
};
getResult.onerror=function(){
console.log("获取数据错误");
};
};
- delete方法
delete方法与get方法的使用方式类似,在没有建立索引的情况下,直接传入key用来删除数据。
-openCursor方法
openCursor方法用来遍历指定仓库中的所有数据,这个操作是异步执行的,所以返回结果会在回调函数中。
req.onsuccess=function(e){
var db=e.target.result;
var t=db.transaction(["user"],"readwrite");
var store=t.objectStore("user");
var cursor=store.openCursor();
cursor.onsuccess=function(event){
var res=event.target.result;
if(res){
var key=res.key;
var value=res.value;
console.log(key+":"+JSON.stringify(value));
res.continue();
}
};
cursor.onerror=function(){
console.log("遍历数据错误");
};
};
返回结果:
6.索引的使用
在实际的开发过程中,我们的查询业务一般是很复杂的,使用一般的get查询不能满足我们的全部需求,在这里我们就要引入“索引”,有了“索引”之后我们就可以根据某些“特殊属性”来查询数据;
- 创建索引
createIndex()方法用于为仓库对象创建一个索引,接受三个参数:索引名称、属性名、参数对象。
req.onupgradeneeded=function(e){
var db=e.target.result;//数据库对象
//判断仓库是否存在
if(!db.objectStoreNames.contains("user")){
//创建仓库
var store=db.createObjectStore("user",{
autoIncrement:true
});
//创建索引
store.createIndex("nameIndex","name",{unique:false});
store.createIndex("ageIndex","age",{unique:false});
}
}
注: unique表示这个索引值在仓库对象中是否唯一
- index方法获取索引
有了索引之后,我们就可以通过索引根据指定的属性来获取数据;index方法可以从仓库对象中返回指定的索引。
var db=myDB.db;
var t=db.transaction(["user"],"readwrite");
var userStore=t.objectStore("user");
var index=userStore.index("ageIndex");
在获取到了指定的索引之后,就可以通过索引来获取数据,这里需要注意的是,获取数据的步骤是异步执行的,只能在回调函数中才能拿到指定的数据。
req.onsuccess=function(e){
var db=e.target.result;
var t=db.transaction(["user"],"readwrite");
var store=t.objectStore("user");
var index=store.index("ageIndex");
var request=index.get(20);
request.onsuccess=function(event){
var data=event.target.result;
};
request.onerror=function(){
console.log("获取失败");
};
};
注: 这里需要注意的是,虽然在数据库中,满足条件的数据有多条,但是实际在返回的时候,只返回了第一条满足条件的数据,如果想要获取更多满足条件的数据,则需要用到游标。
- cursor 游标
在indexedDB数据库中,使用游标和使用索引是分不开的;
仓库对象的openCursor方法,用于创建一个游标;
contine方法会使游标按指定方向移动,直到没有数据的时候返回undefined;
使用游标能够遍历整个仓库的数据,这在前面已经介绍过了,这里不再介绍。
- 索引与游标的共同使用
- 获取指定值得数据 IDBKeyRange.only();
req.onsuccess=function(e){
var db=e.target.result;
var t=db.transaction(["user"],"readwrite");
var store=t.objectStore("user");
var index=store.index("ageIndex");
//获取age=20的所有数据
var request=index.openCursor(IDBKeyRange.only(20*1));
request.onsuccess=function(event){
var cursor=event.target.result;
if(cursor){
var key=cursor.key;
var primaryKey=cursor.primaryKey;
var name=cursor.value.name;
var age=cursor.value.age;
console.info("key:"+key+","+"primaryKey:"+primaryKey+","+"name:"+name+","+"age:"+age);
cursor.continue();
}
};
request.onerror=function(event){
console.log("获取数据错误");
};
};
返回的数据:
-
获取范围数据
利用游标与索引除了可以获取指定值的所有数据之外,还可以获取在一定范围之内的数据;//获取 age >= 20 的数据 包含下限值 IDBKeyRange.lowerBound(20) // age > 20 IDBKeyRange.lowerBound(20,true) //获取 age <= 20 的数据 包含上限值 IDBKeyRange.upperBound(20); // age < 20 IDBKeyRange.upperBound(20,true); //获取 20 <= age <= 24 范围内的值,包含界限值 IDBKeyRange.bound(20,24) // 20 < age <= 24 IDBKeyRange.bound(20,24,true,false) // 20 <= age < 24 IDBKeyRange.bound(20,24,false,true) // 20 < age < 24 IDBKeyRange.bound(20,24,true,true)
-
利用索引进行多条件查询
利用索引与游标可以实现多条件查询数据// 创建索引 store.createIndex('myindex', ['name','age'], {unique:false}); // 利用创建的索引查询数据 var transaction = db.transaction('person','readonly'); var store = transaction.objectStore('person'); var index = store.index('myindex'); // 这里传入的数据 就是具体查询的值 和你创建索引时指定 key 一一对应 var request1 = index.openCursor(IDBKeyRange.only(["yanwu2", 24]),"next"); request1.onsuccess = function(event) { var cursor = event.target.result; // 对获取的值进行遍历 返回的数据并不是一个数组 if (cursor){//如果存在 var stu = cursor.value; console.log(stu); cursor.continue();//继续下一个 } } }
数据源:
查询结果: