indexedDB

422 阅读7分钟

概念

IndexedDB 是一种底层 API,用于在客户端存储大量的结构化数据(也包括文件/二进制大型对象(blobs))。该 API 使用索引实现对数据的高性能搜索。虽然 Web Storage 在存储较少量的数据很有用,但对于存储更大量的结构化数据来说力不从心。而 IndexedDB 提供了这种场景的解决方案。

意思就是IndexedDB主要用来客户端存储大量数据而生的

indexedeDB特点

  • 键值对存储,所有对象都可存储
  • 异步,操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage 形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。
  • 支持事务。一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。
  • 同源限制,不能访问跨域的数据库
  • 支持二进制存储。
  • 存储空间大,一般不小于250MB,无上限

浏览器存储的方式

截图.png

数据库操作

游标cursor:可以把游标想象为一个指针,比如我们要查询满足某一条件的所有数据时,就需要用到游标,我们让游标一行一行的往下走,游标走到的地方便会返回这一行数据,此时我们便可对此行数据进行判断,是否满足条件。 只能通过主键、索引、游标方式查询数据。

创建或打开数据库

window.indexedDB.open(DBName,version)

//  兼容浏览器
 var indexedDB =
      window.indexedDB ||
      window.mozIndexedDB ||
      window.webkitIndexedDB ||
      window.msIndexedDB;
      
//indexedDB数据库.open("数据库名字","版本号-不填默认1-填写只能是整数")  没有创建 有打开库
const request = indexedDB.open('myDatabase', 1);
request.addEventListener('success', e => {
   console.log("连接数据库成功");
});
request.addEventListener('error', e => {
  console.log("连接数据库失败");
});

创建删除一个对象仓库

createObjectStore(storeName,para)第一个是对象仓库的名字,在同一数据库中,仓库名不能重复.第二个是可选参数.用于指定数据的主键,以及是否自增主键

deleteObjectStore(storeName)删除对象仓库

const request = indexedDB.open('myDatabase', 2);

request.addEventListener('upgradeneeded', e => {

  const db1:any=e

  const db = db1?.target.result; //数据库对象

  //将主键设置为keyId

  const  store = db.createObjectStore('storeInfo', {keyPath: 'keyId', autoIncrement: false});

  console.log('创建对象仓库成功');

  

   // 删除仓库对象(删除表格)

   db.deleteObjectStore('storeInfo');

});

要创建一个对象仓库必须在upgradeneeded事件中,而upgradeneeded事件只会在版本号更新的时候触发.这是因为indexedDB API中不允许数据库中的数据仓库在同一版本中发生变化

创建事务

transaction(storeName,pattern)第一参数对象仓库名称,第二参数创建的事务模式readonly只读,readwrite读写

const request = indexedDB.open('myDatabase', 3);
  request.addEventListener('success', e => {

  const db1:any=e

  const db = db1?.target.result;

  //创建事务

  const tx = db.transaction('storeInfo','readwrite');

});

操作数据

 add() : 增加数据。接收一个参数,为需要保存到对象仓库中的对象。

 put() : 增加或修改数据。接收一个参数,为需要保存到对象仓库中的对象。

 get() : 获取数据。接收一个参数,为需要获取数据的主键值。

 delete() : 删除数据。接收一个参数,为需要获取数据的主键值

注:add 和 put 的作用类似, put 保存数据时,如果该数据的主键在数据库中已经有相同主键的时候,则会修改数据库中对应主键的对象,而使用 add 保存数据,如果该主键已经存在,则保存失败

1 数据增删改查

const request = indexedDB.open('myDatabase', 4);

request.addEventListener('success', e => {

    const db = e.target.result;

    const tx = db.transaction('storeInfo','readwrite');

    const store = tx.objectStore('storeInfo');

 

    // 保存数据

    const reqAdd = store.add({'keyId': 1, 'userName': '张三', 'age': 24});

    reqAdd.addEventListener('success', e => {

      console.log('保存成功')

    })


     // 获取数据  参数是主键值

     const reqGet = store.get(1);

     reqGet.addEventListener('success', e => {      

       console.log(reqGet.result.userName);    // 张三

     })

  
      // 删除数据    

      const reqDelete = store.delete(1);    

      reqDelete.addEventListener('success', e => {      

        console.log('删除数据成功');    

      })

});

2 使用游标查询

openCursor(range,direction)

第一个参数是范围,可以是一个IDBKeyRange对象

// boundRange 表示主键值从1到10(包含1和10)的集合。

// 如果第三个参数为true,则表示不包含最小键值1,如果第四参数为true,则表示不包含最大键值10,默认都为false

var boundRange = IDBKeyRange.bound(1, 10, false, false);

 

// onlyRange 表示由一个主键值的集合。only() 参数则为主键值,整数类型。

var onlyRange = IDBKeyRange.only(1);

 

// lowerRaneg 表示大于等于1的主键值的集合。

// 第二个参数可选,为true则表示不包含最小主键1,false则包含,默认为false

var lowerRange = IDBKeyRange.lowerBound(1, false);

 

// upperRange 表示小于等于10的主键值的集合。

// 第二个参数可选,为true则表示不包含最大主键10,false则包含,默认为false

var upperRange = IDBKeyRange.upperBound(10, false);

第二个参数是方向

 next : 游标中的数据按主键值升序排列,主键值相等的数据都被读取

 nextunique : 游标中的数据按主键值升序排列,主键值相等只读取第一条数据

 prev : 游标中的数据按主键值降序排列,主键值相等的数据都被读取

 prevunique : 游标中的数据按主键值降序排列,主键值相等只读取第一条数据

作用:获取一个区间内的数据

// boundRange 表示主键值从1到10(包含1和10)的集合。

// 如果第三个参数为true,则表示不包含最小键值1,如果第四参数为true,则表示不包含最大键值10,默认都为false

var boundRange = IDBKeyRange.bound(1, 10, false, false);

 

// onlyRange 表示由一个主键值的集合。only() 参数则为主键值,整数类型。

var onlyRange = IDBKeyRange.only(1);

 

// lowerRaneg 表示大于等于1的主键值的集合。

// 第二个参数可选,为true则表示不包含最小主键1,false则包含,默认为false

var lowerRange = IDBKeyRange.lowerBound(1, false);

 

// upperRange 表示小于等于10的主键值的集合。

// 第二个参数可选,为true则表示不包含最大主键10,false则包含,默认为false

var upperRange = IDBKeyRange.upperBound(10, false);

3 使用索引游标查询

createIndex(name,keyPath,optionalParameters)

  1. name: 索引名,不能重复.

  2. keypath :对应可以是key值,也可以是一个包含key值集合的数组.

  3. optionalParameters:可选的对象参数{unique, multiEntry}

    •  unique: 用来指定索引值是否可以重复,为true代表不能相同,为false时代表可以相同
    •  multiEntry: 当第二个参数keyPath为一个数组时.如果multiEntry是true,则会以数组中的每个元素建立一条索引.如果是false,则以整个数组为keyPath值,添加一条索引.
// boundRange 表示主键值从1到10(包含1和10)的集合。

// 如果第三个参数为true,则表示不包含最小键值1,如果第四参数为true,则表示不包含最大键值10,默认都为false

var boundRange = IDBKeyRange.bound(1, 10, false, false);

 

// onlyRange 表示由一个主键值的集合。only() 参数则为主键值,整数类型。

var onlyRange = IDBKeyRange.only(1);

 

// lowerRaneg 表示大于等于1的主键值的集合。

// 第二个参数可选,为true则表示不包含最小主键1,false则包含,默认为false

var lowerRange = IDBKeyRange.lowerBound(1, false);

 

// upperRange 表示小于等于10的主键值的集合。

// 第二个参数可选,为true则表示不包含最大主键10,false则包含,默认为false

var upperRange = IDBKeyRange.upperBound(10, false);

4 复合索引查询

const request = indexedDB.open('myDatabase', 6);

request.addEventListener('upgradeneeded', e => {

    const db = e.target.result;

    const  store = db.createObjectStore('storeInfo', {keyPath: 'keyId', autoIncrement: false});

    //创建了多条索引.

    store.createIndex('name','username',{unique: false})

    store.createIndex('age',"userage",{unique: false})

    //  创建复合索引

    store.createIndex("name_age", ["name","age"], { unique: false });

});

const arr = []

request.addEventListener('success', e => {

    const db = e.target.result;//数据库对象

    const tx = db.transaction('storeInfo','readwrite');//事务

    const store = tx.objectStore('storeInfo');//对象仓库

    //使用索引

    const index = store.index('name_age');

    //游标

    const req = index.openCursor(IDBKeyRange.bound(['李四',12],['李四','']));

    req.addEventListener('success', e => {

      const cursor = e.target.result;

        if(cursor){

            arr.push(cursor.value)

            console.log(cursor.value,'复合索引');

            cursor.continue();

        }else{

            console.log('检索结束');

        }

    })

});

5  索引和游标分页查询

//通过索引和游标分页查询记录

let list:any = [];

let counter = 0; // 计数器

let advanced = true; // 是否跳过多少条查询

let page = 1; // 页码

let pageSize = 3; //查询条数

const request = store.index('name').openCursor(IDBKeyRange.only('哈哈'));

request.onsuccess = function (e:any) {

  var cursor = e.target.result;

  if (page > 1 && advanced) {

    advanced = false;

    cursor.advance((page - 1) * pageSize); // 跳过多少条

    return;

  }

  if (cursor) {

    console.log(cursor,"ppq")

    // 必须要检查

     counter++;

    if (counter < pageSize) {

      list.push(cursor.value)

      cursor.continue(); // 遍历了存储对象中的所有内容

    } else {

      cursor = null;

      console.log("分页查询结果", list);

    }

  } else {

    console.log("分页查询结果2", list);

  }

};

request.onerror = function (e:any) { };

6 模糊查询

//模糊查询

//模糊查询

  let inpname = "嘻嘻" //查询是值

  let list:any = [];

  let bol = true;

  let nameArr = inpname.split("");

  if (db != null) {

   const request = store.index('name').openCursor()

    request.onsuccess = (e:any) => {

      if (request.result) {

        let cursor = request.result;

        //模糊查询按字符串查找

        bol = nameArr.every(value => {

          return cursor.key.indexOf(value) > -1;

        });

        if (bol) {

          list.push(cursor.value);

        }

        cursor.continue();

      } else {

        console.log("数据为空");

      }

     };

    request.onerror = (e:any) => {

      console.log("遍历失败", e);

    };

  }

删除数据库

window.indexedDB.deleteDatabase(databaseName);

常用属性方法

wangdoc.com/javascript/…