indexDB 基本用法总结

在项目开发过程中,前端需要存储大量的数据。cookie, localstorage 都有存储长度限制。首先总结一下各个存储的参数

  1. cookie: 一般由服务器生成,可以设置过期时间;前端采用和js-cookie等组件也可以生成,数据存储大小4k,每次都会携带在请求的header 中,对于请求性能有影响;同时由于请求中都带有,所以也容易出现安全问题,字符串键值对在本地存储数据
  2. localStorage: 除非被清理,否则一直存在;浏览器关闭还会保存在本地,但是不支持跨浏览器,大小5MB,不参与服务端通讯,字符串键值对在本地存储数据
  3. sessionStorage:页面关闭就清理刷新依然存在,不支持跨页面交互,大小5MB,不参与服务端通讯,字符串键值对在本地存储数据
  4. indexedDB:除非被清理,否则一直存在,不限制大小,不参与服务端通讯,IndexedDB 是一个非关系型数据库(不支持通过 SQL 语句操作)。可以存储大量数据,提供接口来查询,还可以建立索引,这些都是其他存储方案无法提供的能力。

IndexedDB介绍

IndexedDB 属于非关系型数据库。(不支持SQL查询)

特点:
键值对储存 IndexedDB 内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 JavaScript 对象。对象仓库中,数据以"键值对"的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。
异步 IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage 形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。
支持事务 IndexedDB 支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。
同源限制 IndexedDB 受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。
支持二进制储存 IndexedDB 不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer 对象和 Blob 对象。
储存空间大 IndexedDB 的储存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有上限。储 存 在 电 脑 上 中 的 位 置 为 C:\Users\当 前 的 登 录 用 …\Default\IndexedDB

核心概念
数据库:IDBDatabase 对象,数据库有版本概念,同一时刻只能有一个版本,每个域名可以建多个数据库
对象仓库:IDBObjectStore 对象,类似于关系型数据库的表格
索引: IDBIndex 对象,可以在对象仓库中,为不同的属性建立索引,主键建立默认索引
事务: IDBTransaction 对象,增删改查都需要通过事务来完成,事务对象提供了error,abord,complete三个回调方法,监听操作结果
操作请求:IDBRequest 对象
指针: IDBCursor 对象
主键集合:IDBKeyRange 对象,主键是默认建立索引的属性,可以取当前层级的某个属性,也可以指定下一层对象的属性,还可以是一个递增的整数

indexedDB使用

/**
 * 打开或者创建数据库连接
 * @param {*} dbName 数据库名称
 * @param {*} verson 数据库版本
 */
function openDB(dbName, verson = 1, tableName, uuid) {
  return new Promise((resolve, reject) => {
    const indexdDB = window.indexedDB
    let db
    // 打开数据库,如果没有就创建
    const request = indexdDB.open(dbName, verson)
    // 数据库打开成功的回调
    request.onsuccess = function (event) {
      db = event.target.result // 数据库对象
      console.log('数据库打开成功了')
      resolve(db)
    }
    // 数据库打开失败的回调
    request.onerror = function (event) {
      console.log('数据库打开失败')
      reject(event)
    }
    // 数据库有更新时的回调  数据库创建或者升级的时候会被触发
    request.onupgradeneeded = function (event) {
      db = event.target.result
      let objStorage = {}
      objStorage = db.createObjectStore(
        tableName, // 创建表名称为users
        {
          keyPath: uuid, // 主键
          autoIncrement: true // 是否实现自增
        }
      )
      // 创建索引,在后面查询数据的时候可以根据索引查询
      objStorage.createIndex(uuid, uuid, { unique: true }) // 因为uuid是主键,所以不能为空不可重复
      objStorage.createIndex('name', 'name', { unique: false })
      objStorage.createIndex('age', 'age', { unique: false })
    }
  })
}

/**
 * 插入数据
 * @param {*} db 数据库对象
 * @param {*} storeName 仓库名
 * @param {*} data 插入的数据
 */
function addData(db, storeName, data) {
  return new Promise((resolve, reject) => {
    const request = db
      .transaction([storeName], 'readwrite') // 事物对象 指定表格名称和操作模式 只读 或修改
      .objectStore(storeName) // 创建仓库对象
      .add(data)
    console.log(request, 'request')
    request.onsuccess = function (event) {
      console.log('数据写入成功')
      resolve(event)
    }

    request.onerror = function (event) {
      console.log('数据写入失败')
      reject(event)
    }
  })
}

/**
 * 通过主键查询数据
 * @param {*} db
 * @param {*} storeName
 * @param {*} key 主键名
 * @returns
 */
function getDtaByKey(db, storeName, key) {
  return new Promise((resolve, reject) => {
    const transaction = db.transaction([storeName])
    const objectStore = transaction.objectStore(storeName)
    // const request = objectStore.getAll() // 也是查询表里面的所有数据
    const request = objectStore.get(key)

    request.onsuccess = function (event) {
      console.log('查找成功')
      resolve(event)
    }

    request.onerror = function (event) {
      console.log('查找失败')
      reject(event)
    }
  })
}

/**
 * 开启游标查询
 */
function cursorGetData(db, storeName) {
  return new Promise((resolve, reject) => {
    const list = []
    const store = db.transaction(storeName, 'readwrite').objectStore(storeName)
    const request = store.openCursor() // 指针对象
    // 游标开启成功
    request.onsuccess = function (e) {
      const cursor = e.target.result
      // 注意这个地方需要做判断,当我们没有数据的时候,那么这个值是空的,他会一直执行
      if (cursor) {
        list.push(cursor.value)
        cursor.continue() //继续遍历存储对象中的所有内容
      } else {
        console.log('游标对去的数据', list)
      }
    }

    // 游标开启失败
    request.onerror = function (e) {
      console.log('游标开启失败了')
      reject(e)
    }
  })
}

/**
 * 通过索引查询数据
 * @param {*} db
 * @param {*} storeName
 * @param {*} indexName 索引名称
 * @param {*} indexValue 索引值
 * @returns
 */
function getDataByIndex(db, storeName, indexName, indexValue) {
  return new Promise((resolve, reject) => {
    const store = db.transaction(storeName, 'readwrite').objectStore(storeName)
    const request = store.index(indexName).get(indexValue)
    request.onsuccess = function (e) {
      const result = e.target.result
      resolve(result)
    }
    request.onerror = function (err) {
      console.log(err)
      reject(err)
    }
  })
}

/**
 * 通过游标和索引查询数据
 * @param {*} db
 * @param {*} storeName
 * @param {*} indexName
 * @param {*} indexValue
 * @returns
 */
function cursorGetByIndex(db, storeName, indexName, indexValue) {
  return new Promise((resolve, reject) => {
    let list = []
    const store = db.transaction(storeName, 'readwrite').objectStore(storeName)
    // store.index(indexName) 索引对象   IDBKeyRange.only(indexValue) 只针对想
    const request = store.index(indexName).openCursor(IDBKeyRange.only(indexValue))
    request.onsuccess = function (e) {
      const cursor = e.target.result
      if (cursor) {
        list.push(cursor.value)
        cursor.continue()
      } else {
        console.log('游标索引查询结果', list)
        resolve(list)
      }
    }
    request.onerror = function (e) {
      console.log('查询失败')
      reject(e)
    }
  })
}

function getByIndexPage(db, storeName, indexName, indexValue, page, pageSize) {
  return new Promise((resolve, reject) => {
    let list = []
    let counter = 0 // 计数器
    let advanced = true // 是否跳过多少条查询, 如果是false 查询全部数据
    const store = db.transaction(storeName, 'readwrite').objectStore(storeName)
    const request = store.index(indexName).openCursor(IDBKeyRange.only(indexValue))
    request.onsuccess = function (e) {
      const cursor = e.target.result
      // 查询大于第一页的数据,从第二页开始
      if (page > 1 && advanced) {
        advanced = false
        list.push(cursor.value)
        cursor.advance((page - 1) * pageSize) // 跳过多少条
        return
      }
      if (cursor) {
        list.push(cursor.value)
        counter++
        if (counter < pageSize) {
          cursor.continue()
        } else {
          cursor = null
          console.log('分野查询结果', list)
        }
      } else {
        console.log(list, '分页结果')
      }
    }
    request.onerror = function (e) {
      console.log('查询失败')
      reject(e)
    }
  })
}

/**
 * 更新数据
 */
function upDateDB(db, storeName, data) {
  return new Promise((resolve, reject) => {
    const store = db.transaction(storeName, 'readwrite').objectStore(storeName).put(data)
    request.onsuccess = function (e) {
      const result = e.target.result
      resolve(result)
    }
    request.onerror = function (err) {
      console.log(err)
      reject(err)
    }
  })
}

/**
 * 通过主键删除数据
 */
function deleteDB(db, storeName, id) {
  return new Promise((resolve, reject) => {
    const store = db.transaction(storeName, 'readwrite').objectStore(storeName).delete(id)
    request.onsuccess = function (e) {
      const result = e.target.result
      resolve(result)
    }
    request.onerror = function (err) {
      console.log(err)
      reject(err)
    }
  })
}

/**
 * 通过索引和游标删除数据
 */
function cursorDelete(db, storeName, indexName, indexValue) {
  const store = db.transaction(storeName, 'readwrite').objectStore(storeName)
  const request = store.index(indexName).openCursor(IDBKeyRange.only(indexValue))
  request.onsuccess = function (e) {
    let cursor = e.target.result
    let deleteRequest
    if (cursor) {
      deleteRequest = cursor.delete() // 请求删除当前项
      deleteRequest.onerror = function () {
        console.log('删除失败')
      }
      deleteRequest.onsuccess = function () {
        console.log('删除成功')
      }
    }
  }
}

/**
 * 关闭数据库
 */
function closeDB(db) {
  db.close()
}

/**
 * 删除数据库
 */
function deleteDBALL(dbName) {
  return new Promise((resolve, reject) => {
    let deleteRquest = window.indexedDB.deleteDatabase(dbName)
    deleteRquest.onerror = function () {
      console.log('删除失败')
      resolve(succ)
    }
    deleteRquest.onsuccess = function (err) {
      console.log('删除成功')
      reject(err)
    }
  })
}

/**
 * 生成唯一id的方法
 * @returns
 */
function generateUUID() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
    var r = (Math.random() * 16) | 0,
      v = c === 'x' ? r : (r & 0x3) | 0x8
    return v.toString(16)
  })
}

export {
  openDB,
  addData,
  generateUUID,
  getDtaByKey,
  cursorGetData,
  getDataByIndex,
  cursorGetByIndex,
  getByIndexPage,
  closeDB,
  deleteDBALL
}



 // 添加
    async handleClickA() {
      const db = await openDB('class', 1, 'users', 'uuid')
      let data = {
        uuid: generateUUID(), // 插入uuid时,不能为空否则报错
        name: '你个老六',
        age: Math.round(Math.random() * 30),
        class: [1, 2, 3, 4, 5, 6],
        sex: [{ a: 1, b: 2, c: 3 }]
      }
      await addData(db, 'users', data)
    },

    // 通过主键搜索 某个表里面的某个数据
    async handleClickAsearch() {
      let list = {}
      const db = await openDB('class', 1)
      const res = await getDtaByKey(db, 'users', 'd6f161b7-fe0e-43e3-8e3e-d9a0ddf3951c')
      if (res.type === 'success') {
        list = res.target.result
      }
      console.log(list)
    },
    // 通过游标查询 可以理解为查某个表
    async handleClickAcours() {
      const db = await openDB('class', 1)
      const res = await cursorGetData(db, 'users')
      console.log(res)
    },
    // 通过索引查询
    async handleClickAvalues() {
      const db = await openDB('class', 1)
      const res = await getDataByIndex(db, 'users', 'age', 19)
      console.log(res)
    },
    //通过游标和索引查询数据
    async handleClickAandKey() {
      const db = await openDB('class', 1)
      const res = await cursorGetByIndex(db, 'users', 'age', 19)
      console.log(res)
    },
   // 通过游标和索引查询数据分页
    async handleClickAandKeyPage() {
      const db = await openDB('class', 1)
      const res = await getByIndexPage(db, 'users', 'age', 29, 1, 10)
      console.log(res)
    }

你可能感兴趣的:(vue.js,javascript,前端)