欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

IndexedDB

程序员文章站 2023-11-14 18:31:34
一、IndexedDB 1、简介 随着浏览器功能增强,许多网站开始将大量数据保存在客户端,从而减少从服务器获取数据的操作,提高了响应速度。 cookie 由于大小不超过 4kb,肯定不合适。 LocalStorage 大小在 2.5 - 10 M间(不同浏览器不同,比如Chrome为 5M),且不提 ......

一、indexeddb

1、简介

  随着浏览器功能增强,许多网站开始将大量数据保存在客户端,从而减少从服务器获取数据的操作,提高了响应速度。
  cookie 由于大小不超过 4kb,肯定不合适。
  localstorage 大小在 2.5 - 10 m间(不同浏览器不同,比如chrome为 5m),且不提供索引、查找慢,也不合适。
  indexeddb 就比较合适了,是浏览器提供的本地数据库,它可以被网页脚本创建和操作。indexeddb 允许储存大量数据,提供查找接口,还能建立索引提高查询效率。

2、特点

(1)采用键值对存储。
  indexeddb 内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 javascript 对象。对象仓库中,数据以"键值对"的形式保存。

(2)异步处理。
  indexeddb 操作时采用异步处理,用户可以进行其它操作。

(3)支持事务。
  indexeddb 支持事务,即要么完成、要么失败,不会出现完成一半的状态。

(4)存储空间大、且支持二进制存储。


3、相关概念

(1)数据库(idbdatabase 对象)
  管理、存储数据的仓库。indexeddb 数据库有版本的概念。同一个时刻,只能有一个版本的数据库存在。如果要修改数据库结构(新增或删除表、索引或者主键),只能通过升级数据库版本完成。

(2)对象仓库(idbobjectstore 对象)
  每个数据库都包含若干对象仓库。可以理解为一个个数据表。

(3)数据记录  
  对象仓库中存储的即为数据记录,采用键值对保存。其中键唯一,值可以为任意类型。

(4)索引(idbindex 对象)
  为了提高查询效率,可以根据数据记录的主键建立索引。

(5)事务(idbtransaction 对象)
  数据记录的读写和删改,都要通过事务完成。事务对象提供error、abort和complete三个事件,用来监听操作结果。

(6)操作请求(idbrequest 对象)

(7)指针( idbcursor 对象)
  可用于遍历数据。

(8)主键集合(idbkeyrange 对象)

4、vue使用indexeddb快速入门实例

(1)项目目录结构
  使用vue-cli创建项目。参考:https://www.cnblogs.com/l-y-h/p/11241503.html

IndexedDB

 

 

 (2)完整代码

此处,我将创建一个  “test” 数据库, 其中有一个 “person” 表(对象仓库)

【main.js】
import vue from 'vue'
import app from './app.vue'

vue.config.productiontip = false

new vue({
  render: h => h(app),
}).$mount('#app')



【app.vue】
<template>
    <div>
        <small>添加前请先打开数据库(如数据库不存在则执行创建过程)</small><br /><br />
        <button @click="opendb">打开数据库</button>
        <button @click="deletedb">删除数据库</button><br /><br />
        <button @click="closedb">关闭数据库</button><br /><br />
        姓名:<input type="text" id="name" v-model="name"><br />
        年龄:<input type="number" id="age" min=1 v-model="age"><br />
        性别:
        男:<input type="radio" id="man" name="sex" value="male" v-model="sex">
        女:<input type="radio" id="woman" name="sex" value="female" v-model="sex"><br />

        <button @click="add">添加数据</button>
        <button @click="get">获取数据</button><br /> 
        <button @click="foreach">遍历数据</button><br /> 
        <button @click="update">更新数据</button><br /> 
        <button @click="remove">删除数据</button><br /> 
        <button @click="searchfromindex">根据索引查数据</button><br /> 
    </div>
    <!--app -->
</template>

<script>
    import indexeddb from './indexeddb.js'
    export default {
        data () {
            return {
                name: 'tom',
                age: '12',
                sex: 'male'
            }
        },
        methods: {
            opendb() {
                indexeddb.opendb('test', 'person', 1)
            },

            deletedb() {
                indexeddb.deletedb('test')
            },
            
            closedb() {
                indexeddb.closedb('test')
            },
            
            add() {
                indexeddb.add('person', {name: this.name, age: this.age, sex: this.sex})
            },
            
            get() {
                indexeddb.get('person')
            },
            
            foreach() {
                indexeddb.foreach('person')
            },
            
            update() {
                indexeddb.update('person', {id: 4, name: this.name, age: this.age, sex: this.sex})
            },
            
            remove() {
                indexeddb.remove('person', 4)
            },
            
            searchfromindex() {
                indexeddb.searchfromindex('person', 'name', 'tom')
            }
        }
    }
</script>

<style>

</style>




【indexeddb.js】
// 定义一个全局变量,用于保存数据库连接(开发中应该不会这么写,此处只是帮助理解)
let db = null;  
export default {
    // indexeddb兼容
    indexeddb: window.indexeddb || window.webkitindexeddb || window.msindexeddb || mozindexeddb,

    // 打开数据库
    // dbname指的是 数据库名, version 指的是 版本号
    opendb(dbname, objectstorename, version) {
        // 获取当前数据库版本号
        var version = version || 1

        // 获取数据库连接,若数据库不存在,会创建数据库(异步处理,根据情况自动触发下面三个事件)
        var request = this.indexeddb.open(dbname, version)

        // 获取数据库连接失败
        request.onerror = function(event) {
            console.log('indexeddb数据库打开错误')
        }

        // 获取数据库连接成功 
        request.onsuccess = function(event, callback) {
            db = event.target.result;
            if (callback && (typeof callback === 'function')) {
                callback(db)
            }
            if (db != null) {
                console.log('数据库打开成功')
            }
        }

        // 创建新的储存空间(当第一次创建数据库、或者数据库版本号变化时会触发)
        request.onupgradeneeded = function(event) {
            console.log('数据库版本变化')
            console.log('创建数据库' + dbname)
            // 拿到数据库连接的结果对象
            db = event.target.result;

            // 判断当前数据库中表(对象仓库)是否存在(注意此处是数据库的表名,不是数据库名)
            if (!db.objectstorenames.contains(objectstorename)) {
                // 创建对象仓库,并设置主键自增
                var objectstore = db.createobjectstore(objectstorename, {
                    keypath: 'id',
                    autoincrement: true
                })

                // 创建索引(根据需要创建)
                objectstore.createindex('name', 'name', {
                    unique: false
                })

                objectstore.createindex('age', 'age', {
                    unique: false
                })

                objectstore.createindex('sex', 'sex', {
                    unique: false
                })
            }
        }

    },

    // 删除数据库
    deletedb: function(dbname, callback) {
        // 删除数据库
        var deletequest = this.indexeddb.deletedatabase(dbname);
        
        // 成功删除
        deletequest.onerror = function() {
            console.log('删除数据库出错' + event.target.message)
        }

        // 删除失败 
        deletequest.onsuccess = function() {
            if (callback && (typeof callback === 'function')) {
                callback()
            }
            console.log('删除数据库成功')
        }
    },

    // 关闭数据库 
    closedb: function() {
        if (db != null) {
            db.close()
            db = null
            console.log("数据库关闭")
        }
    },

    // 添加数据
    // 对象仓库(表名),传入的参数
    add: function(objectstorename, argument) {
        if (db != null) {
            console.log(db)
            
            // 执行事务,添加数据到对象仓库(表)
            var request = db.transaction([objectstorename], 'readwrite')
                .objectstore(objectstorename)
                .add(argument);

            request.onsuccess = function(event) {
                console.log('数据写入成功');
            };

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

    // 获取数据
    // 对象仓库(表名)
    get: function(objectstorename) {
        if (db != null){
            console.log(db)
            
            // 执行事务,从对象仓库(表)中获取所有数据
            var request = db.transaction([objectstorename], 'readwrite')
                .objectstore(objectstorename).getall()
            
            // 数据获取失败
            request.onerror = function(event) {
                console.log('事务失败')
            }
            
            //数据获取成功
            request.onsuccess = function(event) {
                if (request.result) {
                    // 打印所有数据
                    console.log(request.result)
                } else {
                    console.log('未获得数据记录')
                }
            };
        }
    },
    
    // 遍历数据
    // 对象仓库(表名)
    foreach: function(objectstorename) {
        if (db != null){
            console.log(db)
            
            // 执行事务,从对象仓库(表)中获取所有数据
            var request = db.transaction([objectstorename], 'readwrite')
                .objectstore(objectstorename).opencursor()
            
            // 数据获取失败
            request.onerror = function(event) {
                console.log('事务失败')
            }
            
            //数据获取成功
            request.onsuccess = function(event) {
                let cursor = request.result
                if (cursor) {
                    // 遍历打印所有数据
                    console.log(cursor)
                    console.log(cursor.key)
                    console.log(cursor.value.name)
                    console.log(cursor.value.age)
                    console.log(cursor.value.sex)
                    cursor.continue()
                } else {
                    console.log('未获得数据记录')
                }
            };
        }
    },
    
    // 更新数据(若数据存在,则覆盖之前的数据,若数据不存在,则新增一个值)
    // 对象仓库(表名)
    update: function(objectstorename, argument) {
        if (db != null) {
            console.log(db)
            
            // 执行事务,添加数据到对象仓库(表)
            var request = db.transaction([objectstorename], 'readwrite')
                .objectstore(objectstorename)
                .put(argument);

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

            request.onerror = function(event) {
                console.log('数据更新失败');
            }
        }
    },
    
    // 删除数据(若数据不存在,则不会执行删除操作)
    // 对象仓库(表名)
    remove: function(objectstorename, index) {
        if (db != null){
            console.log(db)
            
            // 执行事务,从对象仓库(表)中获取所有数据
            var request = db.transaction([objectstorename], 'readwrite')
                .objectstore(objectstorename).delete(index)
            
            // 数据获取失败
            request.onerror = function(event) {
                console.log('事务失败')
            }
            
            //数据获取成功
            request.onsuccess = function(event) {
                if (request.result) {
                    // 遍历打印所有数据
                    console.log(request.result)
                } else {
                    console.log('未获得数据记录')
                }
            };
        }
    },
    
    // 根据索引查值(若数据不存在,返回一个[]数组)
    // 对象仓库(表名)
    searchfromindex: function(objectstorename, index, data) {
        if (db != null){
            console.log(db)
            
            // 执行事务,从对象仓库(表)中获取所有数据
            var request = db.transaction([objectstorename], 'readonly')
                .objectstore(objectstorename).index(index).getall(data)
            
            // 数据获取失败
            request.onerror = function(event) {
                console.log('事务失败')
            }
            
            //数据获取成功
            request.onsuccess = function(event) {
                if (request.result) {
                    // 遍历打印所有数据
                    console.log(request.result)
                } else {
                    console.log('未获得数据记录')
                }
            };
        }
    }
}

(3)截图:
  step1:初始化页面。

IndexedDB

 

 

   step2:点击 打开数据库。

IndexedDB

 

 

   step3:点击添加按钮

IndexedDB

 

 

   step4:改变数据后,再次添加

IndexedDB

 

 

   step5:获取数据(控制台打印)

IndexedDB

 

 

   step6:点击遍历数据按钮

IndexedDB

 

 

   

  step7:更新数据
    以更新id=4为例,此时数据不存在,会新增。

IndexedDB

 

 

   当修改数据后,再次更新,则会覆盖原数据。

IndexedDB

 

 

   step8:根据 name 查询所有 为 tom 的数据。

IndexedDB

 

 

   

  step9:删除第4条数据(根据主键来删,若主键不存在,则不会删除)。
    先获取当前数据。

IndexedDB

 

 

   执行删除后,会删除id=4(id是主键)的数据。

IndexedDB

 

 

   

  step10:关闭、删除数据库
    若先点击 删除按钮,再点击关闭按钮,则删除按钮会等关闭按钮执行后再执行。

IndexedDB

 

 

   此时,test数据库被删除。

IndexedDB

 

 

   

(4)创建、打开数据库
  需使用 indexeddb.open() 方法,返回一个 idbrequest 对象,并可能触发三个事件(onsuccess 、onerror、onupgradeneeded )。

【格式:】
    var request = window.indexeddb.open(databasename, version);

【其中:】
    databasename :为字符串,表示数据库名,不可省略。
    version : 为当前数据库版本,当数据库不存在时,会创建数据库,且默认为1。
        当数据库存在时,若 version 大于当前数据库版本,则会触发数据库升级操作。
        当version 省略时,默认为当前数据库版本。
        
【可能会触发的事件】
    onsuccess 表示成功打开数据库。
    onerror  表示打开数据库失败。
    onupgradeneeded  表示数据库升级事件。当数据库不存在,或者数据库指定版本号大于当前版本时触发。
    
    
【代码:】
// 打开数据库
// dbname指的是 数据库名, version 指的是 版本号
opendb(dbname, objectstorename, version) {
    // 获取当前数据库版本号
    var version = version || 1

    // 获取数据库连接,若数据库不存在,会创建数据库(异步处理,根据情况自动触发下面三个事件)
    var request = this.indexeddb.open(dbname, version)

    // 获取数据库连接失败
    request.onerror = function(event) {
        console.log('indexeddb数据库打开错误')
    }

    // 获取数据库连接成功 
    request.onsuccess = function(event, callback) {
        db = event.target.result;
        if (callback && (typeof callback === 'function')) {
            callback(db)
        }
        if (db != null) {
            console.log('数据库打开成功')
        }
    }

    // 创建新的储存空间(当第一次创建数据库、或者数据库版本号变化时会触发)
    request.onupgradeneeded = function(event) {
        console.log('数据库版本变化')
        console.log('创建数据库' + dbname)
        // 拿到数据库连接的结果对象
        db = event.target.result;

        // 判断当前数据库中表(对象仓库)是否存在(注意此处是数据库的表名,不是数据库名)
        if (!db.objectstorenames.contains(objectstorename)) {
            // 创建对象仓库,并设置主键自增
            var objectstore = db.createobjectstore(objectstorename, {
                keypath: 'id',
                autoincrement: true
            })

            // 创建索引(根据需要创建)
            objectstore.createindex('name', 'name', {
                unique: false
            })

            objectstore.createindex('age', 'age', {
                unique: false
            })

            objectstore.createindex('sex', 'sex', {
                unique: false
            })
        }
    }

}

 

(5)添加数据
  向对象仓库(表)中写入数据记录。需要通过事务完成。
  注意:

    db之前已经声明过全局了,这里直接用(实际开发中应该不允许直接声明,可以通过回调函数来实现,有时间再补充)。
  创建一个事务需要根据 对象仓库名(表名)以及操作模式(readwrite, readonly),创建事务后,通过idbtransaction.objectstore(name)方法,拿到 idbobjectstore 对象,再通过表格对象的add()方法,向表格写入一条记录。

// 添加数据
// 对象仓库(表名),传入的参数
add: function(objectstorename, argument) {
    if (db != null) {
        console.log(db)
        
        // 执行事务,添加数据到对象仓库(表)
        var request = db.transaction([objectstorename], 'readwrite')
            .objectstore(objectstorename)
            .add(argument);

        request.onsuccess = function(event) {
            console.log('数据写入成功');
        };

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

 

(6)读取数据
  需要事务来操作。
  可以objectstore.get(index)、objectstore.getall()方法用于读取数据,参数index是主键的值。

// 获取数据
// 对象仓库(表名)
get: function(objectstorename) {
    if (db != null){
        console.log(db)
        
        // 执行事务,从对象仓库(表)中获取所有数据
        var request = db.transaction([objectstorename], 'readwrite')
            .objectstore(objectstorename).getall()
        
        // 数据获取失败
        request.onerror = function(event) {
            console.log('事务失败')
        }
        
        //数据获取成功
        request.onsuccess = function(event) {
            if (request.result) {
                // 打印所有数据
                console.log(request.result)
            } else {
                console.log('未获得数据记录')
            }
        };
    }
},

 

(7)遍历数据
  需要事务来操作。
  遍历数据表格的所有记录,要使用指针对象 idbcursor,使用objectstore.opencursor()获取。

// 遍历数据
// 对象仓库(表名)
foreach: function(objectstorename) {
    if (db != null){
        console.log(db)
        
        // 执行事务,从对象仓库(表)中获取所有数据
        var request = db.transaction([objectstorename], 'readwrite')
            .objectstore(objectstorename).opencursor()
        
        // 数据获取失败
        request.onerror = function(event) {
            console.log('事务失败')
        }
        
        //数据获取成功
        request.onsuccess = function(event) {
            let cursor = request.result
            if (cursor) {
                // 遍历打印所有数据
                console.log(cursor)
                console.log(cursor.key)
                console.log(cursor.value.name)
                console.log(cursor.value.age)
                console.log(cursor.value.sex)
                cursor.continue()
            } else {
                console.log('未获得数据记录')
            }
        };
    }
},

 

(8)更新数据
  需要事务来操作。
  使用idbobjectstore.put(index)方法可以更新数据,若index存在则覆盖,否则新增一个值。

// 更新数据(若数据存在,则覆盖之前的数据,若数据不存在,则新增一个值)
// 对象仓库(表名)
update: function(objectstorename, argument) {
    if (db != null) {
        console.log(db)
        
        // 执行事务,添加数据到对象仓库(表)
        var request = db.transaction([objectstorename], 'readwrite')
            .objectstore(objectstorename)
            .put(argument);

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

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

 

(9)删除数据
  需要事务来操作。
  idbobjectstore.delete(index)方法用于删除记录,参数index是主键的值。

// 删除数据(若数据不存在,则不会执行删除操作)
// 对象仓库(表名)
remove: function(objectstorename, index) {
    if (db != null){
        console.log(db)
        
        // 执行事务,从对象仓库(表)中获取所有数据
        var request = db.transaction([objectstorename], 'readwrite')
            .objectstore(objectstorename).delete(index)
        
        // 数据获取失败
        request.onerror = function(event) {
            console.log('事务失败')
        }
        
        //数据获取成功
        request.onsuccess = function(event) {
            if (request.result) {
                // 遍历打印所有数据
                console.log(request.result)
            } else {
                console.log('未获得数据记录')
            }
        };
    }
},

 

(10)使用索引
  需要事务来操作。
  根据建立的索引可以很方便的查值。idbobjectstore.index(index)方法用于索引查找,参数index是索引的值。

// 根据索引查值(若数据不存在,返回一个[]数组)
// 对象仓库(表名)
searchfromindex: function(objectstorename, index, data) {
    if (db != null){
        console.log(db)
        
        // 执行事务,从对象仓库(表)中获取所有数据
        var request = db.transaction([objectstorename], 'readonly')
            .objectstore(objectstorename).index(index).getall(data)
        
        // 数据获取失败
        request.onerror = function(event) {
            console.log('事务失败')
        }
        
        //数据获取成功
        request.onsuccess = function(event) {
            if (request.result) {
                // 遍历打印所有数据
                console.log(request.result)
            } else {
                console.log('未获得数据记录')
            }
        };
    }
}

 

(11)删除数据库(会等事务结束再执行)

// 删除数据库
deletedb: function(dbname, callback) {
    // 删除数据库
    var deletequest = this.indexeddb.deletedatabase(dbname);
    
    // 成功删除
    deletequest.onerror = function() {
        console.log('删除数据库出错' + event.target.message)
    }

    // 删除失败 
    deletequest.onsuccess = function() {
        if (callback && (typeof callback === 'function')) {
            callback()
        }
        console.log('删除数据库成功')
    }
},

 

(12)关闭数据库

// 关闭数据库 
closedb: function() {
    if (db != null) {
        db.close()
        db = null
        console.log("数据库关闭")
    }
},

 

二、indexeddb常用方法

  浏览器原生提供indexeddb对象,作为开发者的操作接口。

1、indexeddb.open()

  用于打开数据库。是一个异步操作,但是会立即返回一个idbopendbrequest 对象。

打开一个名为test、版本为1的数据库。如果该数据库不存在,则会新建该数据库。
var openrequest = window.indexeddb.open('test', 1);

触发事件:
    success:打开成功。
    error:打开失败。
    upgradeneeded:第一次打开该数据库,或者数据库版本发生变化。

在success中,可以通过openrequest.result属性拿到已经打开的indexeddb数据库对象。
在upgradeneeded中,可以传入event,通过 event.target.result 拿到已经打开的indexeddb数据库对象。

 

2、indexeddb.deletedatabase()

  用于删除数据库,是一个异步操作,但会立刻返回一个idbopendbrequest对象。

删除名为test的数据库。若数据库不存在,不会报错。
var dbdeleterequest = window.indexeddb.deletedatabase('test');

触发事件:
    success:删除成功。
    error:删除失败。

 

未完待续。。。


参考地址:
  https://wangdoc.com/javascript/bom/indexeddb.html