indexedDB类似nosql的数据库,是面向索引的数据库,相对于web storage,它为web离线存储提供大数据存储和搜索。
浏览器兼容性
使用步骤
操作数据之前,我们先建立一个数据库
/** * 创建数据库 */
function createDB(){
var openReq = window.indexedDB.open(dbName);
openReq.onerror = function(ev){
};
openReq.onsuccess = function(ev){
var db = ev.target.result ;
tip.innerText = "数据库名称 : " + db.name;
};
}
由于indexedDB数据库兼容性还不是很好,需要为各自的对象各自浏览器加上前缀,我们 可以按下面来做统一对象
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;//indexDB对象
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction || {READ_WRITE: "readwrite"}; // 事务对象
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange; //key过滤对象
创建的同时,我也要能删除数据库,我们可以这样子删除数据库
/** * 删除数据库 */
function delDB(){
var openReq = window.indexedDB.deleteDatabase(dbName);
openReq.onerror = function(ev){
};
openReq.onsuccess = function(ev){
tip.innerText = "删除数据库成功";
};
}
上面的操作设计到如下方法和事件
indexedDB的数据库打开是异步操作,需要回调事件才确定打开接口,提供一下事件
三个事件都传事件对象到方法里面,可以通过事件对象获取数据库对象或者结果集,事务对象等等
创建好了数据库之后,我们就来创建一个存储对象,你可以理解为关系数据库中的表,那下面我建一个消费者customers的表
/** *创建一个存储对象 */
function createObjectStore(){
var openReq = window.indexedDB.open(dbName,4); //只有改变版本号才能对该数据库结构和数据进行操作
openReq.onsuccess = function(ev){
tip.innerText = "创建存储对象成功";
};
openReq.onerror = function(ev){
tip.innerText = "失败";
};
openReq.onupgradeneeded = function(ev){//版本号不同调发这个回调
var db = ev.target.result ; //获取数据库对象
//创建表名和主键
var objectStore = db.createObjectStore("customers", { autoIncrement : true}); //创建存储对象,利用autoIncrement主键自动递增
//创建字段索引,索引可以用来搜索,详细看后面
objectStore.createIndex("uid","uid",{unique : true});
objectStore.createIndex("age","age",{unique : false});
objectStore.createIndex("name", "name", { unique: false });
};
}
该创建步骤设计到以下方法
创建primaryKey的时候有俩种方式
俩种的区别,是在更新的时候,”1”的策略,不会更新数据,而是直接向数据库重新插入一条数据,因为主键key每次都是递增不相同。”2”的策略会直接更新数据
createIndex不需要为每个字段建立索引,只需建立你需要的索引就可以了,例如我们把下面的数据类型插到数据库中
const customerData = [ //数据类型json,可以把key理解为字段,建立索引的时候,没必要为每个字段建立索引
{ uid: "aaa", name: "根子", age: 15, email: "[email protected]" },
{ uid: "bbb", name: "花子", age: 11, email: "[email protected]" }
];
/** * 添加一条数据 */
function addData(){
var req = window.indexedDB.open(dbName,15);
req.onupgradeneeded = function(ev){
var db = ev.target.result ;
var transaction = ev.target.transaction || db.transaction(["customers"],IDBTransaction.READ_WRITE); //获取事务
transaction.oncomplete = function(ev){
tip.innerText = "添加数据成功";
};
transaction.onerror = function(ev){
};
var objectStore = transaction.objectStore("customers");//获取事务型的存储对象
for(var i in customerData){
objectStore.add(customerData[i]);
}
}
}
就像关系行数据库一样,在索引数据库中,我们也必须要加上事务控制,避免数据操作不一致。一般读数据,用IDBTransaction.READ,而写数据,我们用IDBTransaction.READ_WRITE关键字来标志
下面我们把更新和删除也举例一下
/** * 更新一条数据 */
function updateData(key,name,age,email){
var req = window.indexedDB.open(dbName,++index);
req.onupgradeneeded = function(ev){
var db = ev.target.result;
var transaction = ev.target.transaction || db.transaction(["customers"],IDBTransaction.READ_WRITE);
var objstore = transaction.objectStore("customers");
var getReq = objstore.get(key); //通过主键直接获取一个对象
transaction.oncomplete = function(ev){
tip.innerText = "更新数据成功";
};
transaction.onerror = function(ev){
};
getReq.onsuccess = function(){ //获取数据成功
var obj = getReq.result; //获取数据对象
obj.ssn = "343tt4343" ;
obj.name = name ;
obj.age = age ;
obj.email = email ;
objstore.put(obj);//更新数据,主键策略不同,更新结果也会不同
}
};
}
/** * 删除一条数据 */
function delData(){
var req = window.indexedDB.open(dbName,++index);
req.onupgradeneeded = function(ev){
var db = ev.target.result;
var transaction = ev.target.transaction || db.transaction(["customers"],IDBTransaction.READ_WRITE);
var objstore = transaction.objectStore("customers");
transaction.oncomplete = function(ev){
tip.innerText = "删除数据成功";
};
transaction.onerror = function(ev){
};
objstore.delete(1);
}
}
任何对数据库的增删改查,都需要加上事务获取事务型的存储对象,可以理解为关系型数据库中的表,先找表,再对表进行CRUD,下面来看看查询操作。
get 通过primary key来获取数据对象
/** * 更新一条数据 */
function findDataByKey(key){
var req = window.indexedDB.open(dbName,++index);
req.onupgradeneeded = function(ev){
var db = ev.target.result;
var transaction = ev.target.transaction || db.transaction(["customers"],IDBTransaction.READ_WRITE);
var objstore = transaction.objectStore("customers");
var getReq = objstore.get(key); //通过主键直接获取一个对象
getReq.onsuccess = function(){ //获取数据成功
var obj = getReq.result; //获取数据对象,auto
...
}
};
}
openCursor 打开游标来遍历数据
/** * 遍历获取全部数据 */
function retriving(){
//1.打开数据库
var req = window.indexedDB.open(dbName,++index);
//2.判断成功,打开事务
req.onupgradeneeded = function(ev){
var db = ev.target.result; //获取数据库对象
var transaction = ev.target.transaction || db.transaction(["customers"],IDBTransaction.READ); //打开事务
var objstore = transaction.objectStore("customers");//获取操作存储对象
var cursor = objstore.openCursor(); //打开游标
cursor.onsuccess = function(ev){
var result = ev.target.result ;
if (result) {
console.log("key = " + result.key + " -- name = " + result.value.name);
result.continue(); //继续遍历
}
else {
tip.innerText = "遍历完成";
}
}
}
}
index 通过索引来获取对象
/** * 用index获取数据 */
function findByIndex(index){
var req = window.indexedDB.open(dbName,++index);
req.onupgradeneeded = function(ev){
var transaction = ev.target.transaction || db.transaction(["customers"],IDBTransaction.READ); //打开事务
var objstore = transaction.objectStore("customers");//获取操作存储对象
var item = objstore.index("name"); //通过建立的name索引来获取对象
item.get("lucy").onsuccess = function(event) {//获取匹配的一条数据
tip.innerText = "lucy's SSN is " + event.target.result.ssn;
};
}
}
通过index获取的数据可能不只一条数据,如果是多条数据,我们也可以继续用游标进行遍历
/** * 用indexcursor来变量列 */
function retrivingByIndexCusor(){
var req = window.indexedDB.open(dbName,++index);
req.onupgradeneeded = function(ev){
var transaction = ev.target.transaction || db.transaction(["customers"],IDBTransaction.READ); //打开事务
var objstore = transaction.objectStore("customers");//获取操作存储对象
var item = objstore.index("name");
item.openCursor().onsuccess = function(ev) {//打开 游标进行遍历
var cursor = ev.target.result;
if (cursor) {
console.log( cursor.key + ", uuid: " + cursor.value.uuid+ ", email: " + cursor.value.email);
cursor.continue();
}
};
}
}
IDBKeyRange 用来做指定获取数据的范围,类型关系型数据中start limit处理分页的一样
/** * 利用keyRange来获取指定范围的的数据 */
function useIDBKeyRange(){
var req = window.indexedDB.open(dbName,18);
req.onupgradeneeded = function(ev){
var transaction = ev.target.transaction || db.transaction(["customers"],IDBTransaction.READ); //打开事务
var objstore = transaction.objectStore("customers");//获取操作存储对象
var item = objstore.index("age");
// 匹配唯一对象
//var singleKeyRange = IDBKeyRange.only(15);
// 匹配age大于15的那些对象,包括age=15那个对象
//var lowerBoundKeyRange = IDBKeyRange.lowerBound(15);
// 匹配age大于15的那些对象,不包括age=15那个对象
//var lower BoundOpenKeyRange = IDBKeyRange.lowerBound("Bill", true);
// 匹配age小于15的那些对象,不包括age=15那个对象
var upperBoundOpenKeyRange = IDBKeyRange.upperBound(15);
//匹配age在15和50中间的对象,不报错15但报错50
//var boundKeyRange = IDBKeyRange.bound(15, 50, false, true);
item.openCursor(upperBoundOpenKeyRange).onsuccess = function(ev) {
var cursor = ev.target.result;
if (cursor) {
console.log( cursor.key + ", SSN: " + cursor.value.ssn + ", email: " + cursor.value.email);
cursor.continue();
}
};
}
}
我们还可以通过”prev”来进行排序
item.openCursor(upperBoundOpenKeyRange,"prev").onsuccess = function(ev) { //默认排序从小到大,prev能从大到小
var cursor = ev.target.result;
if (cursor) {
console.log( cursor.key + ", SSN: " + cursor.value.ssn + ", email: " + cursor.value.email);
cursor.continue();
}
};
当有age获取数据有重复的时候,例如35岁的有很多个,我们可以通过”nextunique”获取唯一的一条数据
item.openCursor(upperBoundOpenKeyRange,"nextunique").onsuccess = function(ev) { //默认排序从小到大,prev能从大到小
var cursor = ev.target.result;
if (cursor) {
console.log( cursor.key + ", SSN: " + cursor.value.ssn + ", email: " + cursor.value.email);
cursor.continue();
}
};
博客参考
https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB