前端本地数据库之IndexedDB

为何出现indexedDB?

随着客户的要求越来越高,浏览器的功能不断增强,越来越多的网站开始考虑,将大量数据储存在客户端,这样可以减少从服务器获取数据,直接从本地获取数据。

然而,现有的浏览器数据储存方案,都不适合储存大量数据、或者并不提供搜索功能,不能建立自定义的索引。所以,需要一种新的解决方案,这就是 IndexedDB 诞生的背景。

何为indexedDB?

IndexedDB 是 HTML5离线存储数据的一种解决方案,是浏览器提供的本地数据库,它可以被网页脚本创建和操作。
IndexedDB 允许储存大量数据,使用索引高效搜索数据进行读写和管理操作。这些都是 LocalStorage 所不具备的。就数据库类型而言,IndexedDB 不属于关系型数据库(不支持 SQL 查询语句),更接近 NoSQL 数据库。

Cookies、Localstorage、SessionStorage、IndexedDB的比较

Cookies Localstorage SessionStorage IndexedDB
生命周期 Expire设置时间 永久储存(可手动清除) 会话级别 永久储存(可手动清除)
储存数据大小 4K左右 5M左右 5M左右 无限储存
与服务器通信 cookie 的数据自动传递到服务器,服务器端也可以写在cookie到服务端 不参与 不参与 不参与
易用性 自己封装方法 原生接口 原生接口 原生接口

indexedDB特性?

1、键值对存储:内部采用对象仓库(Object Store)存放数据,所有类型都可以直接存入(包括javascript对象),每一个数据对象对应为唯一主键(不可重复)。
2、异步:防止大量数据的读写、拖慢网页
3、支持事务:只要有一步失败,整个transaction都取消,不存在只改写一部分数据的情况,安全性更高。
4、同源限制:每一个数据库都有他对应的域名,网页只能访问自身域名对应的数据库,不能跨域访问。
5、存储空间大:IndexedDB 的储存空间比 LocalStorage 大得多,理论上没有上限。
6、支持二进制存储:除了字符串之外,储存二进制数据(ArrayBuffer 对象和 Blob 对象)

indexedDB结构?

类比sql型数据库,IndexedDB中的DB(数据库)就是sql中的DB,而Object Store(存储空间)则是数据表,Item则等于表中的一条数据对象(记录)
在这里插入图片描述

indexedDB怎么玩?

1、创建数据库

/* 调用示例
	var IDB = new OpenIndexDB({
	    "dbname":"newindexdb",//数据库名称,必填
	    "dbversion":1,//数据库版本号 不填则默认 1
	    "store":"personss"//仓库名称 不填则默认 kmgBst
	})
*/

/**
 * [OpenIndexDB 创建一个本地数据库]
 * @param {[Object]} opt [初始属性]
 */
	function OpenIndexDB(opt) {
	  const $this = this
	  // 创建indexedDB对象,兼容各种浏览器
	  const indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB
	  if (!indexedDB) {
	    console.log('indexDB创建失败:你的浏览器不支持IndexedDB')
	    return '创建失败'
	  }
	  if (!opt.dbname) {
	    console.log('indexDB创建失败:indexDB名称不能为空')
	    return '创建失败'
	  }
	  // 初始化属性
	  $this.dbInfo = {
	    name: opt.dbname, // 数据库名称
	    version: opt.dbversion || 1, // 数据库版本号
	    store: opt.store || 'kmgBst', // 仓库名称
	    db: null, // 数据库变量
	    key: opt.key || 'key' // 关键字
	  }
	  // 创建indexDB
	  $this.opendb()
	}

2、创建indexDB

/**
 * [opendb 创建indexDB]
 */
	OpenIndexDB.prototype.opendb = function() {
	  // 定义indexDB的各项信息
	  const $this = this
	  const dbname = this.dbInfo.name
	  const dbversion = this.dbInfo.version
	  const storeName = this.dbInfo.store
	  const key = this.dbInfo.key
	  // 打开一个数据库
	  const request = indexedDB.open(dbname, dbversion)
	  // 打开失败
	  request.onerror = function(e) {
	    console.log(e.currentTarget.error.message)
	  }
	  // 打开成功!
	  request.onsuccess = function(e) {
	    $this.dbInfo.db = e.target.result
	    console.log('成功打开' + dbname)
	  }
	  // 打开成功后,如果版本有变化自动执行以下事件
	  request.onupgradeneeded = function(e) {
	    var db = e.target.result
	    if (!db.objectStoreNames.contains(storeName)) {
	      // 如果表格不存在,创建一个新的表格(keyPath,主键 ; autoIncrement,是否自增),会返回一个对象(objectStore)
	      var objectStore = db.createObjectStore(storeName, {
	        keyPath: 'id',
	        autoIncrement: true
	      })
	      // 指定可以被索引的字段,unique字段是否唯一, 指定索引可以加快搜索效率。
	      objectStore.createIndex(key, key, {
	        unique: true
	      })
	    }
	    console.log('数据库版本更改为: ' + dbversion)
	  }
	}

indexedDB.open()方法返回一个 IDBRequest 对象。这个对象通过三种事件error、success、upgradeneeded,处理打开数据库的操作结果。

3、设置数据 setData

/**
 * [setData 设置数据]
 * @param {[Object]} opt [要储存的数据]
 */
	OpenIndexDB.prototype.setData = function(opt) {
	  // 定义indexDB的各项信息
	  const $this = this
	  const db = this.dbInfo.db
	  const storeName = this.dbInfo.store
	  const key = this.dbInfo.key
	  // 创建一个事务
	  const transaction = db.transaction(storeName, 'readwrite')
	  // 通过事务来获取store
	  const store = transaction.objectStore(storeName)
	  // 构建数据对象
	  const obj = {}
	  obj[key] = opt.key
	  obj['value'] = opt.value
	  // 往数据库添加数据
	  const addData = store.add(obj)
	  addData.onsuccess = function(e) {
	    console.log('数据添加成功')
	  }
	  addData.onerror = function(e) {
	    // 数据已存在就更新数据
	    if (e.target.error.code === 0) {
	      $this.updateData(opt.key, opt.value)
	    }
	  }
	}

4、获取数据

/**
 * [getData 获取数据]
 * @param  {[String]} keyname [通过key值名称获取数据]
 * @param  {[Function]} callback [回调函数]
 */
	OpenIndexDB.prototype.getData = function(keyname, callback) {
	  if (!keyname) { return }
	  // 定义indexDB的各项信息
	  const db = this.dbInfo.db
	  const storeName = this.dbInfo.store
	  const key = this.dbInfo.key
	  // 创建一个事务
	  const transaction = db.transaction(storeName, 'readwrite')
	  // 通过事务来获取store
	  const store = transaction.objectStore(storeName)
	  // 根据索引获取数据
	  const index = store.index(key)
	  // 根据指定的keyname获取数据
	  const request = index.get(keyname)
	  // 成功获取数据时调用
	  request.onsuccess = function(e) {
	    const data = e.target.result
	    // 调用回调函数
	    callback(data)
	  }
	  request.onerror = function(e) {
	    console.log(e)
	  }
	}

5、更新数据

/**
 * [updateData 更新数据]
 * @param  {[String]} keyname  [通过key值名称获取数据]
 * @param  {[Any]} updateData [原本的数据、替换的数据]
 * @param  {[String]} addKey  [添加的值,有该值代码在原值后面增加,否则updateData 全部替换初始值]
 */
	OpenIndexDB.prototype.updateData = function(keyname, updateData, addKey) {
	  if (!keyname) { return }
	  // 定义indexDB的各项信息
	  const db = this.dbInfo.db
	  const storeName = this.dbInfo.store
	  const key = this.dbInfo.key
	  // 创建一个事务
	  const transaction = db.transaction(storeName, 'readwrite')
	  // 通过事务来获取store
	  const store = transaction.objectStore(storeName)
	  // 根据索引获取数据
	  const index = store.index(key)
	  // 根据指定的keyname获取数据
	  const request = index.get(keyname)
	  // 成功获取数据时调用
	  request.onsuccess = function(e) {
	    const data = e.target.result
	    // 改变数据
	    if (addKey) {
	      data['value'][addKey] = updateData
	    } else {
	      data['value'] = updateData
	    }
	    // 更新数据
	    store.put(data)
	  }
	  request.onerror = function(e) {
	    console.log(e)
	  }
	}

6、删除数据库

/**
 * [deleteDatabase 删除数据库]
 * @param  {[String]} bdName  [数据库名称]
 */
	OpenIndexDB.prototype.deleteDatabase = function() {
	  const bdName = this.dbInfo.name
	  if (!bdName) { return }
	  var DBDeleteRequest = window.indexedDB.deleteDatabase(bdName)
	  DBDeleteRequest.onerror = function(event) {
	    console.log('Error')
	  }
	  DBDeleteRequest.onsuccess = function(event) {
	    console.log('success')
	  }
	}

7、调用例子

/**
 * VUE项目为例
 * 在mian.js中引入IndexDB文件
 * 创建数据库
 */
	Vue.prototype.$indexDB = new IndexDB({
	  dbname: 'Test', // 数据库名称
	  dbversion: 1, // 版本号
	  store: 'billStore' // 表名称
	})
/**
 * VUE项目为例
 * 设置数据
 */
	this.$indexDB.setData({
       key: 'dictionary',
       value: {d: 12}
     })
/**
 * VUE项目为例
 * 获取数据数据
 */
 	// 引入GETIndexDataCallback
 	import GETIndexDataCallback from '@/utils/get-indexedDB-callback'
 	import { getDictionaryList } from '@/api/common'
 	
 	const opt = {
        dbName: this.$indexDB, // 数据库名称
        key: 'Dictionary',
        api: getDictionaryList // api接口,找不到数据后,请求的接口
      }
      GETIndexDataCallback(opt, (data) => {
        console.log(data)
      })
/**
 * VUE项目为例
 * 封装获取数据,因为很多获取的时候获取可能是空的,所以需要调接口,所以综合一个方法请求
 */
 	
	function GETIndexDataCallback(opt, callback) {
	  if (!opt.dbName) {
	    return
	  }
	  // 未setData直接getData,会transaction找不到
	  try {
	    opt.dbName.getData(opt.key, function(data) {
	       // sessionStorage.getItem('setIndexedDB')是用于每次进来都更新的依据,这里可以接口自定义
	      if (data && sessionStorage.getItem('setIndexedDB')) {
	        callback && callback(data.value)
	      } else {
	        request()
	      }
	    })
	  } catch {
	    request()
	  }
	  // 调接口
	  async function request() {
	    try {
	      const res = await opt.api()
	      if (res && res.status === 0) {
	        let typeObj = res.data
	        opt.dbName.setData({
	          key: opt.key,
	          value: typeObj
	        })
	        sessionStorage.setItem('setIndexedDB', 1)
	        callback && callback(typeObj)
	      }
	    } catch {
	      console.log('res')
	    }
	  }
	}
	
	export default GETIndexDataCallback
	

8、导图
创建导图
前端本地数据库之IndexedDB_第1张图片
调用导图
前端本地数据库之IndexedDB_第2张图片

你可能感兴趣的:(前端)