indexedDB 前端数据库(使用的简单案例)

前端存储 之 indexDB

1、indexedDB是什么?
  • indexedDB是一个非关系型数据库

  • 它不需要我们去写一些特定的SQL语句来对数据库进行操作

  • 它是NoSQL的,数据形式使用的json

2、indexedDB出现的意义?
  • 前端存储,已经有了LocalStorage 和 Cookies ,但是它们都是比较简单的技术。

  • 而indexedDB提供了 类似数据库风格的数据储存 和 使用方式

  • Cookies只能是字符串,储存空间有限,每次HTTP接受和发送都会传递Cookies数据,它会占用额外的流量

  • LocalStorage是用key-value 键值模式储存数据,想让localstorage存储对象,你需要借助JSON.stringify() 能将对象变成字符串形式,再用JSON.parse() 将字符串还原成对象,当存储的数据庞大时,这就不是最佳的方案了,localstorage就是专门为小数量数据设计的,它的api设计为同步的

  • indexedDB很适合存储大量数据,它的API是异步调用的,indexedDB使用索引存储数据,各种数据库操作放在事务中执行,indexedDB支持简单的数据类型,它比localstorage强大,API也相对复杂,对于简单的数据,还是使用localstorage。

  • indexedDB能提供更为复杂的查询数据的方式

3、indexedDB的特性
  • 对象仓库(objectStore)

    • indexedDB没有表的概念,而是使用objectStore。

    • 一个数据库中可以包含多个objectStore

    • objectStore是一个灵活的数据结构,可以存放多种类型数据,也就是说一个objectStore相当于一张表,里面储存的每条数据和一个键相关。

    • 我们可以使用每条记录中的某个字段作为键值(keyPath),也可以使用自动生成的递增数字作为键值(keyGenerator),也可以不指定。

    • 选择键的类型不同,objectStore可以存储的数据结构也有差异

  • 事务性

    • 在indexedDB中,每一个对数据库操作是在一个事务的上下文中执行的。

    • 事务范围一次影响一个或多个objectstores。

    • 你通过传入一个objectstores名字的数组到创建事务 范围的函数来定义

      • 比如: db.transaction( storeName, ' readwrite' ),创建事务的第二个参数是事务模式,当请求一个事务时,必须决定是按照只读还是读写模式模式请求访问

  • 基于请求

    • 对indexedDB数据库的每次操作,描述为通过一个请求打开数据库,访问一个object store,再继续。

    • indexedDB API天生是基于请求的,这也是API异步本性指示,对于你在数据库执行的每次操作,你必须首先为这个操作创建一个请求,当请求完成,你可以响应由请求结果产生的事件和错误

  • 异步

    • 在indexedDB 大部分操作并不是我们常用的调用方法,返回结果的模式,而是请求 ----> 响应的模式

    • 所谓异步API是指并不是这条指令执行完毕,我们就可以使用 request.result 来获取 indexedDB 对象了。

    • 类似于 我们使用ajax一样,语句执行完并不代表已经获取到了对象,所以我们一般在其回调函数中处理。

4、玩 indexedDB 的基本步骤

  1. 打开数据库并且开始一个事务

  2. 创建一个 object store

  3. 构建一个请求执行一些数据库操作,比如新增或者提取数据等

  4. 通过监听正确类型的DOM事件可以等待操作完成

  5. 在操作结果上进行一些操作(可以在 request 对象中找到)

代码案例:

1、打开数据库,需要当前浏览器支持indexedDB

var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
​
if( !indexedDB ){
    alert('当前不支持 indexedDB 数据库');
    throw Error('当前不支持 indexed 数据库');
}

2、创建数据库

function createDB(dbName, version) {
    // 参数为:数据库名和版本号
    // 数据库存在则打开,否则创建
    let request = indexedDB.open(dbName, version);
    /**
     * request 并不会返回一个DB对象的句柄,我们得到的是一个IDBOpenDBRequest对象
     * 而我们期望得到的DB对象在其result属性中
     * 除了 result,IDBOpenDBRequest 接口定义了几个重要属性
     * onerror:请求失败的回调函数句柄
     * onsuccess:请求成功的回调函数句柄
     * onupgradeneeded:请求数据库版本变化句柄
     * 第一次打开数据库,会先触发 onupgradeneeded 事件,然后触发success事件。
     */
    console.log(request);
​
    // 请求数据库失败的回调函数
    request.onerror = function(err) {
        console.log(JSON.stringify(err));
        console.log('打开数据库失败,错误信息为:' + err.target.message);
    }
​
    // 请求数据库成功的回调函数
    request.onsuccess = function(success) {
        console.log(JSON.stringify(success));
        console.log('打开数据库成功:' + success.target.result);
​
        /**
         *  获取数据库实例对象,
         *  db.createObjectStore('table6',{keyPath:'stuId',autoIncrement:true});
         *  var len = db.objectStoreNames.length; --> 对象储存空间名的个数
         *  var name = db.objectStoreNames[1]; --> 对象存储空间名
         *  transaction = db.transaction(['table'],'readwrite'); --> 事务操作的对象存储空间名,事务模式:'readwrite'可读写模式
         * 
         *  // 向info储存空间加入一个info对象,获得request对象用于处理用户对数据库的操作请求
         *  // 同样拥有 onerror 、onupgradeneeded 、onsuccess 事件
         *  objectStore = transaction.objectStore('table');
         */
        let db = success.target.result;
    }
​
    // 数据库版本更新
    request.inuparadeneeded = function(event) {
        console.log(JSON.stringify(event));
        console.log('数据库版本有变化...');
​
        let db = event.target.result;
​
        // 判断对象储存空间名称是否存在
        if (!db.objectStoreNames.contains('table')) {
​
​
            //创建信息对象存储空间;指定keyPath选项为Id(即主键为Id)
            let objectStore = db.createObjectStore('table', {
                keyPath: 'stuId',
                autoIncrement: true
            });
            /*
             *db.createObjectStore("table1", {keyPath: "userId",autoIncrement: true});
             *db.createObjectStore("table2", {keyPath: "userId",autoIncrement: true});
             *db.createObjectStore("table3", {keyPath: "userId",autoIncrement: true});
             *db.createObjectStore("table4", {keyPath: "userId",autoIncrement: true});
             *当然了。你可以一次性的在这里建立多个对象空间 或者每次改变 version和对象空间的名字。之前创建的会存在。
             * 为什么在onupgradeneeded中创建呢?
             * 原因:当dbName和 version 这两个参数中的任何一个发生变化。都会执行重新创建一遍对象空间,
             * 注意:当dbName,保持不变,version 只能逐渐增加,假如你这次 version = 3.那么下次 version = 2.就会报错 打开数据库失败:
             * version!=0;
             * */
​
​
            // 创建索引
            // 索引名,创建索引的列,索引选项(索引属性值是否唯一:true or false)
            // 注意: 创建索引 要在创建对象空间的时候
            // unique:true 实际效果:这个索引的内容是唯一的,不能重复,无法创建两个(索引属性值)相同的内容
            objectStore.createIndex('studentIndex', 'stuId', {
                unique: true
            });
        }
    }
​
}

3、删除数据库 or 关闭数据库

// 关闭与删除数据库
function deleteDB(dbName) {
​
    try {
        // 删除数据库使用 indexedDB对象的deleteDatabase方法
        let request = indexedDB.deleteDatabase(dbName);
​
        request.onerror = function() {
            console.log('删除[' + dbName + ']数据库失败!!!!');
        }
​
        request.onsuccess = function() {
            console.log('删除[' + dbName + ']数据库成功!!!!');
        }
​
    } catch (e) {
        console.log('删除[' + dbName + ']数据库出现错误,' + e.getMessage);
    }
}
​
// 关闭数据库
function colseDB(dbName){
    dbName.close();
}

4、新增数据

// 新增数据
// 数据库名称,对象仓库(表名),传入的参数
function insert(dbName, objectStoreName, argument) {
    // 打开数据库
    let request = indexedDB.open(dbName);
    // 请求数据库成功的回调函数
    request.onsuccess = function(success) {
        // 获取数据库实例对象
        let db = success.target.result;
        // 对某个表 进行事务操作的事务权限控制 
        let transaction = db.transaction(objectStoreName, 'readwrite');
        // 对表进行操作
        let objectStore = transaction.objectStore(objectStoreName);
​
        // 使用add方法,此方法是异步的
        // 有success,error事件
        //objectStore.add(argument);
        // 使用定义add方法
        let add = objectStore.add(argument);
        
        let msg = JSON.stringify(argument);
        
        // 添加成功的回调函数
        add.onsuccess = function(e) {
            console.log(e);
            console.log('向表[' + objectStoreName + ']新增一条数据为[' + msg + ']成功!!');
        }
        add.error = function(e) {
            console.log('向表[' + objectStoreName + ']新增一条数据为[' + msg + ']失败!!');
        }
    }
​
}
​
var stu1 = {
    name: '欧可乐',
    age: 19,
    sex: '男'
};
​
 insert('studentDB','student',stu1);
​

5、查询数据

// 查询数据
// 数据库名,对象仓库(表名),查询参数(键名对应的值)
function getData(dbName, objectStoreName, selectArgument){
    // 打开数据库
    let request = indexedDB.open(dbName);
    // 请求打开数据库的回调函数
    request.onsuccess = function(success){
        let db = success.target.result;
        let transaction = db.transaction([objectStoreName],'readwrite');
        let objectStore = transaction.objectStore(objectStoreName);
        let getResult = objectStore.get(selectArgument);
​
        getResult.onsuccess = function(e){
            console.log( e.target.result);
        }
​
    }
​
}
​
getData('studentDB','student',1);

6、更新数据

// 更新数据
// 数据库名,表名,要更新数据的标志(id),新的数据
function update(dbName, objectStoreName, id, newsData) {
    // 打开数据库
    let request = indexedDB.open(dbName);
    // 请求打开数据库的回调函数
    request.onsuccess = function(success) {
        // 获取到数据库的表
        let db = success.target.result;
        // 对表操作进行事务权限控制
        let transaction = db.transaction(objectStoreName, 'readwrite');
        // 对表进行操作
        let objectStore = transaction.objectStore(objectStoreName);
        // 根据键值 获取某个实例中的某条数据
        let getResult = objectStore.get(id);
        // 实例成功的回调函数
        getResult.onsuccess = function(e) {
            // 源数据
            let msg = e.target.result;
            let old = JSON.stringify(msg);
            // 重新赋值
            msg.name = newsData.name;
            msg.age = newsData.age;
            msg.sex = newsData.sex;
            objectStore.put(msg);
            console.log('更新主键为 stuId:' + msg.stuId + '的数据,原数据:[' + old + '],新数据为:[' + JSON.stringify(e.target.result) +
                        '],更新成功!!!');
        }
        // 实例失败的回调函数
        getResult.onerror = function(e) {
            console.log('数据更新失败!!');
        }
    }
}
​
let stu2 = {
    name: '小可乐',
    age: 18,
    sex: '男'
}
update('studentDB', 'student', 1, stu2);

7、删除数据

// 删除数据
// 数据库名,表名,主键
function deleteData(dbName, tableName, id){
    // 打开数据库
    let request = indexedDB.open(dbName);
    // 请求打开数据库成功的回调函数
    request.onsuccess = function(success){
        // 获取实例
        let db = success.target.result;
        // 事务权限控制
        let transaction = db.transaction(tableName, 'readwrite');
        // 进行操作
        let objectStore = transaction.objectStore(tableName);
        // 进行删除
        let deleteMsg = objectStore.delete(id);
        deleteMsg.onsuccess = function(e){
            console.log('成功删除主键stuId为:' + id+',的数据,状态为:'+e.isTrusted);
        }
    }
}
​
deleteData('studentDB','student',1);

8、清除表数据

// 清空表数据
// 数据库名称,表名
function clearData(dbName, tableName) {
    // 请求打开数据库
    let request = indexedDB.open(dbName);
    // 请求成功的回调函数
    request.onsuccess = function(e) {
        // 获取实例
        let db = e.target.result;
        // 表名事务权限控制
        let transaction = db.transaction(tableName, 'readwrite');
        // 进行操作
        let objectStore = transaction.objectStore(tableName);
        // 清除数据
        let clearResult = objectStore.clear();
        // 清除成功的回调函数
        clearResult.onsuccess = function(e) {
            console.log('表名[' + tableName + ']数据清除成功,状态为:' + e.isTrusted );
        }
    }
}
clearData('studentDB', 'student');

9、使用索引查询

// 利用索引查询
// 数据库,表名,索引名, 查询的值
function searchIndex(dbName, tableName, indexName, indexValue) {
    // 请求打开数据
    let request = indexedDB.open(dbName);
    // 请求打开数据库成功的回调函数
    request.onsuccess = function(e) {
        // 获取到实例
        let db = e.target.result;
        // 赋予事务权限
        let transaction = db.transaction(tableName, 'readwrite');
        // 基于权限进行操作
        let objectStore = transaction.objectStore(tableName);
        // 索引
        let index = objectStore.index(indexName);
        // 获取结果
        let result = index.get(indexValue);
        // 结果获取成功的回调函数
        result.onsuccess = function(e) {
            console.log('索引名:' + indexName + ',索引值:' + indexValue + ',查询的结果:[' + JSON.stringify( e.target.result ) + ']');
        }
    }
}
searchIndex('studentDB','student','studentIndex',2);

10、使用游标读取全部的数据

// 使用 游标
// 数据库名称,表名
function readAll(dbName, tableName) {
    // 请求打开数据库
    let request = indexedDB.open(dbName);
    // 请求成功的回调函数
    request.onsuccess = function(e) {
        // db = e.target.result // 获取实例
        // transaction = db.transaction(tableName,'readwrite'); // 权限控制
        // objectStore = transaction.objectStore(tableName); // 进行操作对象
        let objectStore = e.target.result.transaction(tableName, 'readwrite').objectStore(tableName);
        // 打开游标
        let cursor = objectStore.openCursor();
​
        // 储存值
        let arr = [];
​
        // 成功打开游标的回调函数
        cursor.onsuccess = function(e) {
            let result = e.target.result;
​
            if (result) {
                // 将数据一条一条保存到arr中
                arr.push(result.value);
                result.continue();
            } else {
                if (!arr) {
                    console.log('没有数据....');
                } else {
                    console.log('[' + tableName + ']表中的数据为:' + JSON.stringify(arr));
                }
            }
        }
    }
}
readAll('studentDB', 'student');
posted @ 2019-04-18 09:53  追梦滴小蜗牛  阅读(6184)  评论(0编辑  收藏  举报