IndexedDB简介

IndexedDB是一种可以让你在用户浏览器中持久存储数据的方法,对于需要存储大量数据或者离线的web应用都可以考虑使用,相比已经被废弃的WebSQL,目前来看是IndexedDB未来一种的趋势,并且兼容性比较友好(见下图),如果储存有限的localStorage(具体大小看各家浏览器支持),不能满足你当前的使用需求,可以考虑使用IndexedDB。
IndexedDB的存储空间取决于硬盘大小和浏览器限制规则,正常情况一定会远远大于localStorage的普遍5M。
另外IndexedDB也遵从同源协议(same-origin policy),只能访问同域中存储的数据。

目前各大浏览器对于IndexedDB的兼容

indexedDB各大浏览器支持

*数据来源于 caniuse

IndexedDB主要特点

  • 键值对(Key-Value)存储: key具有唯一性,每个key都对应一个value,key可以是对象自身的属性,value能够直接支持复杂的对象结构,另外key可以是二进制对象。
  • 支持事物(transaction): IndexedDB是事务模式的数据库,一切操作都发生在事务中,索引(indexes)表(tables)指针(cursors)这些都必须依赖于事物,另外事物本身具有生存周期,只能在生存周期内使用,并且事物只能自动提交,不可以手动操作。
  • 异步: IndexedDB的API不通过return语句返回数据,而是需要回调函数来接受数据。执行API时,会向数据库发送一个请求。当操作完成时,数据库会以事件的方式进行通知你,同时事件的类型会告诉你这个操作是否成功。
  • 面向对象: indexedDB不是用二维表来表示集合的关系型数据库。

基础操作

1.打开/新建 数据库

indexedDB.open( databaseName, version )
databaseName: 数据库的名字,如果当前数据库不存在则就会新建,若存在就是打开。
version: 数据库的版本,可省略,若省略,新增时默认为1,打开时默认为当前版本。
现在创建一个新的数据库

window.indexedDB.open('firstDB')

indexedDB.open()会返回一个IDBRequest对象( IDBRequest对象表示打开的数据库连接,使用open()deleteDatabase()都会返回这个对象,对于数据库的操作都是基于这个对象 )
在执行open操作后我们需要关注IDBRequest对象的三个事件,success 打开数据库成功、upgradeneeded 数据库升级(当前指定的版本大于实际版本)、error 打开数据库失败。

const dbName = "firstDB"
let messageList = [],
    request, db
request = window.indexedDB.open(dbName, 1)
request.onerror = function(event) { 
  //错误处理
  console.error('数据库异常')
}
request.onsuccess = function(event) { 
  //成功
  db = request.result //获取数据库对象
}
request.onupgradeneeded = function(event) { 
  //版本变更
  db = event.target.result //更新数据库对象
}

2.创建对象仓库

在数据库第一次创建的时候,version经历了从无到有的变更,所以会触发onupgradeneeded事件.
需要关注点 1.keyPath主动设置主键,2.createIndex创建索引。

const dbName = "firstDB"
let messageList = [],
    request, db
(function() {
  'use strict'
  if (!('indexedDB' in window)) {
    //检查当前浏览器是否支持indexedDB
    alert("Your browser doesn't support a stable version of IndexedDB.")
    return
  }
  request = window.indexedDB.open(dbName, 1)
})()

request.onerror = function(event) { 
  //错误处理
  console.error('数据库异常')
}
request.onsuccess = function(event) { 
  //成功
  db = request.result //获取数据库对象
}
request.onupgradeneeded = function(event) { 
  //版本变更
  db = event.target.result //更新数据库对象
  let objectStore
  if(!db.objectStoreNames.contains('message')) { //检查是否存在message 
    //不存在则创建message keyPath主动设置主键 { keyPath: 'id' } autoIncrement自动生成主键
    //新建索引 参数分别为索引名称、索引所在的属性、配置对象 unique是否允许重复值
    objectStore = db.createObjectStore('message',{ autoIncrement: true } ) 
    objectStore.createIndex('time', 'time', { unique: true }) 
    objectStore.createIndex('content', 'content', { unique: false })
  }
}

3.插入、读取、遍历、更新、删除数据

插入
需要关注点 创建事物 transaction() 第一个参数 涉及操作的objectStore
第二个参数 操作类型 可省略 默认只读 readonly只读 readwrite读写

function writeData(params) {
  //创建事物 第一个参数 涉及的objectStore 
  //第二个参数 操作类型 可省略 默认只读 readonly只读  readwrite读写
  let req = db
    .transaction(['message'], 'readwrite')
    .objectStore('message')
    .add(params)
  req.onsuccess = function (event) {
    console.info('写入成功')
  }
  req.onerror = function (event) {    
    console.error('写入失败: ' + event.srcElement.error.message )
  }
}

读取、查找

function readData() {
  let transaction = db.transaction(['message']),
      objectStore = transaction.objectStore('message'),
      req = objectStore.get(1)
  req.onsuccess = function() {
    if(req.result) {
      //读取成功
      console.log(req.result)
    }
  }
  req.onerror = function() {
    console.error('读取失败')
  }
}
function findData(key, value) {
  let transaction = db.transaction(['message'], 'readonly'),
      store = transaction.objectStore('message'),
      index = store.index(key), //对应的key
      req = index.get(value) //对应查找的值
  req.onsuccess = function(event) { //操作成功
    let result = event.target.result
    if(result) { //存在结果
      console.log(result)
    }
  }
}

遍历数据、获取全部数据

function traversalData() {
  let objectStore = db.transaction('message').objectStore('message')
  // openCursor(range, direction) range 对象来限制被检索的项目的范围, direction可以指定你希望进行迭代的方向
  objectStore.openCursor().onsuccess = function(event) {
    let cursor = event.target.result
    if(cursor) {
      messageList.push(cursor.value)
      cursor.continue() //继续执行
    }
    else {
      console.info('获取完毕')
    }
  }
}
function readAllData() {
  //一次性获取全部数据
  let objectStore = db.transaction('message').objectStore('message'),
      allRecords = objectStore.getAll()
  allRecords.onsuccess = function() {
    messageList = allRecords.result
  }
}

更新、删除

function updateData(params) {
  let req = db
  .transaction(['message'], 'readwrite')
  .objectStore('message')
  .put(params)
  req.onsuccess = function(event) {
    // 数据已更新
  }
  req.onerror = function(event) {
    // 错误处理
  }
}
function deleteData(key) {
  let req = db
  .transaction(['message'], 'readwrite')
  .objectStore('message')
  .delete(key)
  req.onsuccess = function(event) {
    console.info('数据删除成功')
  }

}

IDBRequest对象、IDBCursor对象概念强化

IDBRequest对象属性是由IDBRequest接口返回的事件处理函数的访问结果集,结果集来自对数据库和数据库对象发起的异步查询。我们所有对IndexedDB数据库的读写操作全部都要通过request的方式来实现。request对象初始时不包括任何关于操作结果的信息,当request上的事件触发时,可以通过IDBRequest实例上的事件处理函数访问相关信息。
IDBCursor 接口返回一个游标,能够用于遍历数据库中的记录。游标包含一个源,指向需要遍历的索引或者对象存储区。它在所属区间范围内有一个位置,可以根据记录key的顺序递增或递减方向移动。游标使应用程序能够异步处理在游标范围内的所有记录,同时允许在同一时间拥有无数个游标。

提醒

因为数据存在用户本地,当发生用户主动去清除数据,浏览器处于隐私模式退出,用户硬盘容量到达上限,硬盘文件发生损坏等情况下使用都会受影响。


清水
26 声望2 粉丝

清水既心、