持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情
一. 前言
目前很多浏览器端据存储方案都不适合存储大量数据,例如Cookies容量不超过4KB,localStorage一般浏览器支持是5M大小,对前端大数据存储有点力不从心。为此,浏览器端的数据存储需要种新的技术方案,IndexedDB应运而生。
IndexedDB是HTML5提供的内置于浏览器中的数据库,它可以通过网页脚本程序创建和操作。IndexedDB允许储存大量数据,并且提供查询接口建立索引的功能。就数据库类型而言,IndexedDB不属于关系型数据库(不支持SQL查询语句),更接近文档型数据库。
二. indexedDB特点
(1) 键值对储存
IndexedDB内部采用对象仓库(ObjectStore)存放数据,所有类型的数据都可以直接存入包括JavaScript对象。在对象仓库中,数据以“键值对”的形式保存,每一个数据都有对应的键名且键名必须是唯一的,否则会抛出错误。
(2) 异步API
IndexedDB数据库在执行增、删、改、查操作时不会锁死浏览器,用户依然可以进行其他操作。与localStorage的同步设计相比,IndexedDB的异步设计可以防止大量数据读写时拖慢网页加载速度,而影响用户的网站体验。
(3) 支持事务
IndexedDB支持事务,所以一系列操作步骤中,只要有一步失败,这个事务就都取消,数据库回滚到事务发生之前的状态。举个例子,一次操作需要在一 个数据表中同时插入两条数据,第1条数据插入成功,第2条数据插入失败。那么,对于整个操作来说,两条数据都插入成功才算成功,失败时便需要事务的回滚,将已经插入的第1条数据清除。
(4) 同域限制
IndexedDB也受到同域限制,每-一个数据库对应创建该数据库的域名,来自不同域名的网页只能访问自身域名下的数据库,而不能访问其他域名下的数据库。
(5) 存储空间大
IndexedDB的存储空间比localStorage大得多,一般来说不少于250MB。不同浏览器的限制不同,IE的储存上限是250MB,Chrome和Opera浏览器的存储上限是硬盘剩余空间的某个百分比,Firefox浏览器则没有上限。
(6)支持二进制储存
IndexedDB不仅可以存储字符串,还可以储存二进制数据。
三. 基本使用
3.1 打开/新建数据库
const indexedDB = window.indexedDB || window.webkitindexedDB || window.msIndexedDB || window.mozIndexedDB; //兼容多种浏览器
var request = indexedDB.open(databaseName, version);
databaseName:数据库名称,如果指定数据库不存在,则会新建该名称的数据库
version:整数,表示数据库的版本号。打开已有数据库默认为当前版本。新建数据库时,默认版本号为1。
indexedDB.open()方法返回一个 IDBRequest 对象。这个对象通过以下三种事件处理打开数据库的操作结果。
(1)onerror:打开失败
request.onerror = function (event) {
console.log('数据库打开报错');
};
(2)onsuccess:打开成功
var db;
request.onsuccess = function (event) {
db = event.target.result;
};
(3)onupgradeneeded:据库版本升级或创建数据库时触发,在该事件中创建数据表
var db;
request.onupgradeneeded = function (event) {
db = event.target.result;
if (!db.objecttables.contains('table')) { //判断数据库中是否已经存在该名称的数据表
objectStore = db.createObjectStore('table', { keyPath: 'id' }); //主键为id
objectStore.createIndex('age', 'age', { unique: true }); //添加索引,三个参数分别表示为 索引名称,索引所在的属性,该属性是否包含相同的值
}
}
3.2 新增数据
function addData() {
var request = db.transaction(['table'], 'readwrite') //readwrite表示有读写权限
.objectStore('table')
.add({ id: 1, name: '小明', age:18}); //新增数据
request.onsuccess = function (event) {
console.log('数据写入成功');
};
request.onerror = function (event) {
console.log('数据写入失败');
}
}
addData();
3.3 修改数据
function updateData() {
let request = db.transaction(['table'], 'readwrite') //readwrite表示有读写权限
.objectStore('table')
.put({ id: 1, name: '小明', age: 24}); //新增数据
request.onsuccess = function (event) {
console.log('数据写入成功');
};
request.onerror = function (event) {
console.log('数据写入失败');
}
}
updateData();
3.4 读取数据
function read() {
const transaction = db.transaction(['table']);
const objectStore = transaction.objectStore('table');
const request = objectStore.get(1); //通过主键获取对应数据
//也可以使用索引自定义字段进行搜索
// let index = objectStore.index('name');
// const request = index.get("小明");
request.onerror = function(event) {
console.log('数据读取失败');
};
request.onsuccess = function( event) {
if (request.result) {
console.log(request.result);
} else {
console.log('未获得数据记录');
}
};
}
read();
3.5 删除数据
function removeData() {
let request = db.transaction(['table'], 'readwrite')
.objectStore('table')
.delete(1);
request.onsuccess = function (event) {
console.log('数据删除成功');
};
}
removeData();
//通过游标和索引删除数据
function cursorDeleteData(){
//通过游标删除记录
let store = db.transaction(['table'],'readwrite').objectStore('table');
let request = store.openCursor();
request.onsuccess = function(e){
let cursor = e.target.result,
deleteRequest;
if(cursor){
deleteRequest = cursor.delete();//请求删除当前项
deleteRequest.onerror = function(){
console.log('游标删除该记录失败');
};
cursor.continue();
}
};
}
3.6 清空表所有数据
function clearData(){
//删除存储空间全部记录
let store = db.transaction(['table'],'readwrite').objectStore('table');
let request = store.clear();
request.onerror = function () {
//....
}
request.onsuccess = function () {
//....
}
}
clearData();
3.7 删除数据库
indexedDB.deleteDatabase(DatabaseName);
四. indexedDB封装与实践
export default {
// indexedDB兼容
indexedDB: window.indexedDB || window.webkitindexedDB || window.msIndexedDB || window.mozIndexedDB,
// 打开数据库
// 新对象储存空间newStore参数:{name: "model",keyPath: "panelId"}
openDB: function (dbname, version, newStore) {
return new Promise(resolve=>{
let newVersion = version || 1;
let request = this.indexedDB.open(dbname, newVersion); //数据库名、版本号
request.onerror = function () {
console.log("IndexedDB数据库打开失败")
}
request.onsuccess = function (event) {
let db = event.target.result;
resolve(db)
}
// onupgradeneeded,调用创建新的储存空间(版本升级也会触发)
request.onupgradeneeded = function (event) {
let db = event.target.result;
if (newStore) {
if (!db.objectStoreNames.contains(newStore.name)) {
//新建一个model表格,主键为panelId
let objectStore = db.createObjectStore(newStore.name, {
keyPath: newStore.keyPath //主键keyPath='panelId'
})
console.log(objectStore)
//这里可以添加索引
// objectStore.createIndex('email', 'email', { unique: true });
}
}
}
})
},
//删除数据库
deleteDB: function (dbname) {
return new Promise(resolve=>{
let deleteQuest = this.indexedDB.deleteDatabase(dbname);
deleteQuest.onerror = function () {
console.log("删除数据库出错")
resolve(false)
}
deleteQuest.onsuccess = function () {
console.log("删除数据库成功")
resolve(true)
}
})
},
//关闭数据库
closeDB: function (db) {
db.close();
console.log("数据库已关闭")
},
//写入数据
addData: async function(db, storeName, objValue) {
if(!db){
db = await this.openDB("modelData",1,{name:'model',keyPath:'panelId'});
}
let request = db.transaction(storeName, 'readwrite').objectStore(storeName).add(objValue)
request.onerror = function () {
// console.log("数据写入失败/已存在")
}
request.onsuccess = function () {
// console.log("数据写入成功")
}
},
//根据板件id更新数据
updateData: function (db, storeName, panelId, obj) {
let transaction = db.transaction(storeName, 'readwrite');
let store = transaction.objectStore(storeName);
let request = store.get(panelId); //根据主键删除
return new Promise((resolve, reject) => {
request.onsuccess = function (e) {
let stocktable = e.target.result;
if (stocktable) {
stocktable.modeldata = obj
resolve(store.put(stocktable)); //IDBObject.put()方法
} else {
reject(false);
}
}
})
},
//删除数据
deleteData: function (db, storename, panelId) {
let store = db.transaction(storename, 'readwrite').objectStore(storename);
let request = store.delete(panelId); //IDBObjectStore.delete()
return new Promise(resolve => {
request.onerror = function () {
console.log("删除失败");
resolve(false)
}
request.onsuccess = function () {
console.log("删除成功")
resolve(true)
}
})
},
//清空表所有数据
clearStoreData: async function (db, storename) {
if(!db){
db = await this.openDB("modelData",1,{name:'model',keyPath:'panelId'});
}
let store = db.transaction(storename, 'readwrite').objectStore(storename);
let request = store.clear();
return new Promise(resolve => {
request.onerror = function () {
resolve(false)
}
request.onsuccess = function () {
resolve(true)
}
})
},
//读取数据
read: function (db, storename, panelId) {
let store = db.transaction(storename, 'readwrite').objectStore(storename);
let request = store.get(panelId); //通过主键获取对应数据objectStore.get()
return new Promise(resolve => {
request.onerror = function () {
console.log("单条数据读取失败")
resolve(false)
}
request.onsuccess = function (event) {
resolve(event.target.result);
}
})
},
//读取所有数据
readAll: function (db, storename) {
var objectStore = db.transaction(storename).objectStore(storename);
let request = objectStore.openCursor(); //openCursor()遍历数据
var dataList = [];
return new Promise((resolve) => {
request.onerror = function () {
console.log("单条数据读取失败")
resolve(false)
}
request.onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
dataList.push(cursor.value)
cursor.continue();
} else {
resolve(dataList);
}
};
})
},
//通过索引查找信息
readDataByIndexes: function (db, storename, indexValue,queryData) {
let store = db.transaction(storename, 'readonly').objectStore(storename);
let index = store.index(indexValue); //xxx值初始化数据库onupgradeneeded新建的索引objectStore.createIndex
let request = index.get(queryData);
return new Promise(resolve => {
request.onerror = function () {
console.log("根据索引读取数据失败")
resolve(false)
}
request.onsuccess = function (event) {
resolve(event.target.result);
}
})
}
}
//调用
import myDB from "@/assets/js/indexedDB.js";
this.IndexedDB = await myDB.openDB("modelData", 1, {
name: "model",
keyPath: "panelId",
});