webSQL关系型数据库

  • 存在兼容性问题,ie和火狐均不支持。

在这里插入图片描述

indexDB非关系型数据库:
主要特点

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

在以下情况下,数据库可能被清除:

  • 用户请求清除数据。
  • 浏览器处于隐私模式。最后退出浏览器的时候,数据会被清除。
  • 硬盘等存储设备的容量到限。
  • 不正确的
  • 不完整的改变.

基本概念

  • 数据库(IDBDatabase 对象)数据库是一系列相关数据的容器。每个域名(严格的说,是协议 + 域名 + 端口)都可以新建任意多个数据库。但是它版本的概念。同一个时刻,只能有一个版本的数据库存在。如果要修改数据库结构(新增或删除表、索引或者主键),只能通过升级数据库版本完成。
  • 对象仓库(IDBObjectStore 对象)每个数据库包含若干个对象仓库(object store)。它类似于关系型数据库的表格。
  • 索引(IDBIndex 对象)为了加速数据的检索,可以在对象仓库里面,为不同的属性建立索引。
  • 事务(IDBTransaction 对象)数据记录的读写和删改,都要通过事务完成。事务对象提供error、abort和complete三个事件监听操作结果。
  • 操作请求(IDBRequest 对象)。
  • 指针 (IDBCursor 对象)。
  • 主键集合 (IDBKeyRange 对象)。
    在这里插入图片描述

indexDB新旧版本迁移

代码示例:

创建数据库实例

  • 在生成一个 indexDB 实例时,需要手动指定一个版本号
  • 不允许数据库中的数据仓库在同一版本中发生变化. 并且当前 DB 版本不能和低版本的 version 连接。
  • 若要新增字段等改变数据库的结构就需要改变版本
var db = null;
var db_table = null;
var databaseName = 'indexDB';
var version = 1;
var data = [{  
      id:1,
      name:'张一',
      age:  1,
      email:'zhangsan@example.com' 
  },{  
      id:2,
      name:'张二',
      age:  2,
      email:'zhangsan@example.com' 
  },{  
      id:3,
      name:'张三',
      age:  3,
      email:'zhangsan@example.com' 
  },{  
      id:4,
      name:'张四',
      age:  4,
      email:'zhangsan@example.com' 
  },{  
      id:5,
      name:'张五',
      age:  5,
      email:'zhangsan@example.com' 
  }]

/*
*@databaseName 数据仓库的名字
*@version 数据仓库的版本
*@databaseName 数据仓库的名字
*/

var request = window.indexedDB.open(databaseName, version);
 
/*
*数据仓库打开失败
*/
request.onerror = function (error){
     console.log('IndexDB打开失败',error);
}
 
/*
*数据仓库打开成功
*/
request.onsuccess = function (res){
     console.log('IndexDB打开成功',res);
     db = res.target.result;
}
 
/*
*数据仓库升级事件(第一次新建库是也会触发,因为数据仓库从无到有算是升级了一次)
*/
request.onupgradeneeded = function (res){
     console.log('IndexDB升级成功',res);
     db = res.target.result;
     db_table = db.createObjectStore('group', { keyPath: 'id' });
     db_table.createIndex('indexName', 'name', { unique: false });
}

新建库、表和表指定字段的索引

request.onupgradeneeded = function (res){
     console.log('IndexDB升级成功',res);
     /*
     *返回indexDB对象
     */
     db = res.target.result;
     
     /*
     *创建数据仓库
     *@params 数据仓库名
     *@params 数据仓库配置项 keypath:主键,也可以 autoIncrement: true 自动生成
     */
     db_table = db.createObjectStore('group', { keyPath: 'id' });
     
     /*
     *创建数据索引
     *@params 索引名称
     *@params 索引所在的属性
     *@params 配置对象(说明该属性是否包含重复的值)
     *即indexName这个索引指向了name字段
     */
     db_table.createIndex('indexName', 'name', { unique: false });
}

新增数据

  • 必须通过事务完成
/*
*新建事务
*@params 数据仓库的数组
*@params 写入模式
*/
var store = db.transaction(['group'], 'readwrite').objectStore('group');

/*
*add方法添加数据
*@params 需要添加的数据信息
*/
var request = store.add({
    id:new Date().getTime(),
    name:'王二',
    age:12,
    email:'XXXX@xxx.com'
});

/*
*添加成功
*/
request.onsuccess = function (event) {
    console.log('数据添加成功',event);
};

/*
*添加失败
*/
request.onerror = function (event) {
    console.log('数据添加失败',event);
};

读取数据

/*
*新建事务
*@params 数据仓库的数组
*/
var store = db.transaction(['group']).objectStore('group');

/*
*get方法获取数据
*@params 数据的主键
*/
var request = store.get(1); 

/*
*获取成功
*/
request.onsuccess = function (event) {
    if(event.target.result){
        console.log('数据获取成功',event);
    }
    else{
        console.log('未获取到数据');
    }
};

/*
*获取失败
*/
request.onerror = function (event) {
    console.log('数据获取失败',event);
};

批量读取数据

  • 通过openCursor,传入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 : 游标中的数据按主键值降序排列,主键值相等只读取第一条数据
*/

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

request.addEventListener('success', e => {
    const db = e.target.result;

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

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

    const range = IDBKeyRange.bound(1,10);

    const req = store.openCursor(range, 'next');

    req.addEventListener('success', e => {
      const cursor = this.result;
        if(cursor){
            console.log(cursor.value.userName);
            cursor.continue();
        }else{
            console.log('检索结束');
        }
    })
});

/*
使用cursor.value拿到数据.
使用cursor.updata()更新数据.
使用cursor.delete()删除数据.
使用cursor.continue()读取下一条数据.
*/

更新数据

/*
*新建事务
*@params 数据仓库的数组
*@params 写入模式
*/
var store = db.transaction(['group']).objectStore('group');

/*
*put方法根据主键更新数据
*@params 数据的主键
*/
var request = store .put({  
                          id:1,
                          name:'张一'+Math.random(),
                          age:  24,
                          email:'zhangsan@example.com' 
                      });

/*
*更新成功
*/
request.onsuccess = function (event) {
    console.log('数据更新成功',event);
};

/*
*更新失败
*/
request.onerror = function (event) {
    console.log('数据更新失败',event);
};

删除数据

/*
*新建事务
*@params 数据仓库的数组
*/
var store = db.transaction(['group']).objectStore('group');

/*
*delete方法删除数据
*@params 数据的主键
*/
var request = store.delete(1); 

/*
*删除成功
*/
request.onsuccess = function (event) {
    console.log('数据删除成功',event);
};

/*
*删除失败
*/
request.onerror = function (event) {
    console.log('数据删除失败',event);
};

使用索引

  • 如果不建立索引,只能从定义的主键去查找
/*
*新建事务
*@params 数据仓库的数组
*/
var store = db.transaction(['group']).objectStore('group');

/*
*index方法获取索引对象
*get方法获取数据
*@params 数据的索引
*/
var request = store.index('indexName').get('张四'); 

/*
*获取成功
*/
request.onsuccess = function (event) {
     console.log('通过索引获取数据成功',event);
};

/*
*获取失败
*/
request.onerror = function (event) {
    console.log('通过索引获取数据失败',event);
};

使用索引区间

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

request.addEventListener('upgradeneeded', e => {
    const db = e.target.result;
    const  store = db.createObjectStore('Users', {keyPath: 'userId', autoIncrement: false});
    const idx = store.createIndex('ageIndex','age',{unique: false})
});

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

request.addEventListener('success', e => {
    const db = e.target.result;

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

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

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

    const req = index.openCursor(IDBKeyRange.lowerBound(20), 'next');

    req.addEventListener('success', e => {
      const cursor = e.target.result;
        if(cursor){
            console.log(cursor.value.age);
            cursor.continue();
        }else{
            console.log('检索结束');
        }
    })
});

遍历数据

/*
*新建事务
*@params 数据仓库的数组
*/
var store = db.transaction(['group']).objectStore('group');

/*
*openCursor方法获取指针对象
*get方法获取数据
*@params 数据的索引
*/
var request = store.openCursor();;

/*
*指针对象打开成功
*/
request.onsuccess = function (event) {
     var cursor = event.target.result;
     if(cursor){
         console.log('数据遍历',cursor.value);
         cursor.continue();
     }
     else{
         console.log('没有更多数据了');
     }
};

/*
*指针对象打开失败
*/
request.onerror = function (event) {
    console.log('数据遍历失败');
};

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐