• 【indexedDB】indexedDB知识梳理



    indexedDB介绍


    1)IndexedDB是浏览器提供的本地数据库,具有以下特点:

    • 键值对存储

    • 异步操作

    • 支持事务。这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,

      数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。

      数据库几乎所有操作,都是通过事务来处理的。

    • 受浏览器同源限制。每一个数据库对应创建它的域名。

      网页只能访问自身域名下的数据库,而不能访问跨域的数据库。

    • 储存空间大。一般来说不少于 250MB,甚至没有上限。

    • 支持二进制储存。 IndexedDB 不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer 对象和 Blob 对象)。

    • 几乎所有操作都有成功和失败的监听。


    2) 它包含很多对象接口:

    • 数据库:IDBDatabase 对象
    • 对象仓库:IDBObjectStore 对象
    • 操作请求:IDBRequest 对象
    • 事务: IDBTransaction 对象
    • 索引: IDBIndex 对象
    • 指针: IDBCursor 对象

    等。

    更多接口可在MDN上查看和学习。


    3) 本篇全文两万字,内容是按照整个学习流程,从外到内进行梳理的,

    几乎每个知识都会有相应示例。

    初次接触可以逐步阅读,熟悉后,可以当作一个语法查阅手册。

    本篇只梳理了知识点,后续将发布更多实战操作。

    4) 欢迎访问自己写的一个开放了部分功能的小网站,

    有建议和意见,在上面随便提。域名过期了,还没补。

    http://81.68.151.74/
    
    • 1

    目前在开发网页版微信,有兴趣可以一起讨论。


    数据库操作IDBFactory


    增(连接)

    使用数据库,就必须先创建和连接一个数据库,然后才能对数据库进行其他操作。

    // 处理兼容性问题
    window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
    // open方法创建并连接一个数据库
    const request = window.indexedDB.open(dbname, dbversion)
    // dbname:数据库名字
    // dbversion:数据库版本号,可以不写,默认为1
    // indexedDB遵守同源策略,在同一个源下,dbname是不能重复的,
    // 同一个dbname,也只会存在一个对应的版本号
    // 如果dbname不存在,就创建并打开;如果已存在,就直接打开
    // indexedDB喜欢把一些操作称为'请求',所以用了'request'变量。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    // 删除数据库
    window.indexedDB.deleteDatabase(dbname);
    
    • 1
    • 2

    window.indexedDB.databases()
    .then(database => console.log(database))
    // database是一个列表
    // 列表中每一项包含数据库名称和版本号
    [
        {
            "name": "ok", // 数据库名称
            "version": 2  // 对应版本号
        },
        {
            "name": "todoList",
            "version": 1
        }
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    请求操作IDBRequest


    打开数据库后,得到一个请求对象request

    const request = window.indexedDB.open(dbname, [dbversion])
    console.log('request: ', request);
    // 打印内容:
    {
        error: null,
        onblocked: null,
        onerror: null,
        onsuccess: null,
        onupgradeneeded: f,
        readyState: "done",
        result: {
            name: 数据库名称,
            version: 数据库版本号,
            objectStoreNames: 对象仓库名称列表
        },
        source: null,
        transaction: 数据库事务
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    request中有个result字段和一些on事件,可以使用该字段和相应的事件,处理请求结果。


    onsuccess

    打开数据库成功后执行。每次open成功后都会调用一次。

    request.onsuccess = function(e) {
        console.log('打开数据库成功')
        const db = this.result;
    }
    
    • 1
    • 2
    • 3
    • 4

    onerror

    打开数据库失败时执行。每次open失败后调用。

    request.onerror = function(e) {
        console.log('打开数据库失败: ', request.error);
    }
    
    • 1
    • 2
    • 3

    示例:

    // 假设当前数据库名称为'test', version为2
    // 此时,打开test版本为1的话,就会触发onerror
    window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
    let db;
    const request = window.indexedDB.open('test', 1);
    request.onerror = function() {
    	console.log('open error: ', request.error);
    }
    // error
    open error:  DOMException: The requested version (1) is less than the existing version (2).
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    onupgradeneeded

    监听数据库版本更新。

    1)新建数据库时会调用

    2)数据库版本升级时会调用

    而且,该方法的调用,是在onsuccess之前执行。

    request.onupgradeneeded = function(e) {
        const db = this.result;
        console.log('数据库新的版本号是:', db.version);
    }
    
    • 1
    • 2
    • 3
    • 4

    示例1:

    新建数据库ok

    window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
    let db;
    const request = window.indexedDB.open('songs');
    request.onerror = function() {
    	console.log('open error: ', request.error);
    }
    request.onsuccess = function() {
    	db = this.result;
    	console.log('open success, dbbase current version: ', db.version);
    }
    request.onupgradeneeded = function() {
    	console.log('open upgrade...');
    }
    // 打印结果:
    // open upgrade...
    // open success, dbbase current version:  1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    示例2:

    数据库版本升级时,原来默认的版本是1,现在改为2

    window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
    let db;
    const request = window.indexedDB.open('songs', 2);
    request.onerror = function() {
    	console.log('open error: ', request.error);
    }
    request.onsuccess = function() {
    	db = this.result;
    	console.log('open success, dbbase current version: ', db.version);
    }
    request.onupgradeneeded = function() {
    	console.log('open upgrade...');
    }
    // 打印结果:
    // open upgrade...
    // open success, dbbase current version:  2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    result

    result是数据库请求对象request的属性之一,它对应的是IDBDatabase

    即数据库对象。后续的操作,都是基于该对象来实现的。

    看看result里都有什么?

    window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
    let db;
    const request = window.indexedDB.open('songs', 2);
    request.onsuccess = function() {
    	console.log('request: ', request.result);
    	db = this.result;
    }
    // 打印结果
    IDBDatabase {
    	name: 'songs',
        version: 2,
        objectStoreNames: 对象库名称列表
     	onabort: null,
        onclose: null,
        onerror: null,
        onversionchange: null
    }
    // 原型中还有:
    {
        close: f, // 关闭数据库
        createObjectStore: f, // 创建对象库
        deleteObjectStore: f, // 删除对象库
        transaction: f // 处理事务的方法
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    操作对象库IDBObjectStore


    什么是对象库

    数据库可以理解为一个个数据表单组成的,其中,每一个表单,就是一个对象库。

    比如,我们有一个名为职业的数据库,职业中的教师、医生、码农,都是职业中

    一个下级表单,分别是一个对象库。主要是按照一定的规则操作数据。


    1)语法:

    // storeName 对象库名称
    // option 配置项,可选的,用来设置keyPath
    const objectStore = db.createObjectStore(storeName, option)
    
    // 对象库里都有哪些项,比如姓名 年龄等
    // indexName 姓名 年龄等具体的项
    // keyPath 该项的查询路径,一般和indexName的值一样
    // option 可选,如unique,为true则表示同一个项的值不能重复
    objectStore.createIndex(indexName, keyPath, option);
    // 删除具体的项
    objectStore.deleteIndex(indexName);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2)只能在onupgradeneeded方法中添加对象库

    个人认为原因有2:

    添加对象库的操作只需要在新建数据库或版本更新时进行;

    onupgradeneededonsuccess优先调用,应该更早的创建好对象库,以免报错。

    示例:

    数据库jobs里,创建了三个对象库teacher , doctor, developer

    window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
    let db;
    const request = window.indexedDB.open('jobs');
    request.onerror = function() {
    	console.log('open error: ', request.error);
    }
    request.onsuccess = function() {
    	console.log('request: ', request.result);
    	db = this.result;
    }
    request.onupgradeneeded = function() {
    	console.log('open upgrade...');
    	db = this.result;
    	if(!db.objectStoreNames.contains('teacher')) {
    		db.createObjectStore('teacher', { keyPath: 'id' });
             objectStore.createIndex('name', 'name', { unique: true });
    		objectStore.createIndex('age', 'age', { unique: false })
    	}
    	if(!db.objectStoreNames.contains('doctor')) {
    		db.createObjectStore('doctor', { keyPath: 'id' });
    	}
    	if(!db.objectStoreNames.contains('developer')) {
    		db.createObjectStore('developer', { keyPath: 'id' });
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    db.deleteObjectStore(storeName);
    
    • 1

    事务对象IDBTransaction

    对表单的每一项操作,必须通过具体的事务来完成,一个事务就是一个transaction.

    事务是对象库接口的API

    操作事务在request.onsuccess中完成。


    transaction

    事务。

    语法:

    // 创建事务
    const transaction = db.transaction(storeNames, mode, options)
    // storeNames对象库名称列表。如['teacher', 'doctor'],
    // 如果只写一个对象库名称,可以写成字符串,如'teacher'
    // mode 权限
    // 在对象库内的数据需要变动时,需要设置权限为'readwrite',可读可写
    // 在查询对象库数据时,权限可以设置为'readonly',只读模式
    // options,配置项,可选的。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    此时,要操作哪个对象库,就通过transaction.objectStore获取该对象库的事务

    const store = transaction.objectStore(storeName);
    // storeName 对象库名称
    
    • 1
    • 2

    操作对象库事务的结果有成功和失败事件来监听:

    // 这里的res是sotre操作对应的方法后的执行结果,后面会提到
    res.onerror = function() {
        console.log('处理事务失败...')}
    res.onsuccess = function() {
        console.log('处理事务成功...');
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    往对象库内增加数据。

    语法:

    const res = store.add(data);
    res.onerror = function() {
        // res.error是失败的原因
        console.log('处理事务失败: ', res.error)}
    res.onsuccess = function() {
        // res.result是增加的该项数据的keyPath值
        console.log('处理事务成功: ', res.result);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    注意事项:

    1)添加的数据中,必须包含keyPath值,不然就报错

    Failed to execute 'add' on 'IDBObjectStore': Evaluating the object store's key path did not yield a value.
    
    • 1

    2)添加数据时,keyPath值不能重复,也不能是已经存在的keypPath值,

    不然就添加失败。

    假定keyPath为'id',且id的值1已经存在,此时再重复添加:
    const res = store.add({ id: 1, name: 'liushishi', age: 20 });
    就会触发onerror:
    add data error:  DOMException: Key already exists in the object store.
    
    • 1
    • 2
    • 3
    • 4

    示例:

    window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
    let db;
    const request = window.indexedDB.open('jobs');
    request.onerror = function() {
    	console.log('open error: ', request.error);
    }
    request.onsuccess = function() {
    	console.log('request: ', request.result);
    	db = this.result;
    	// 增
    	const transaction = db.transaction('teacher', 'readwrite');
    	const store = transaction.objectStore('teacher');
    	const res = store.add({ id: 1, name: 'dilireba', age: 18 });
    	res.onerror = function() {
    		console.log('add data error: ', res.error);
    	}
    	res.onsuccess = function() {
    		console.log('add data success: ', res.result); // 1
    	}
    }
    request.onupgradeneeded = function() {
    	console.log('open upgrade...');
    	db = this.result;
    	if(!db.objectStoreNames.contains('teacher')) {
    		const objectStore = db.createObjectStore('teacher', { keyPath: 'id' });
    		objectStore.createIndex('name', 'name', { unique: true });
    		objectStore.createIndex('age', 'age', { unique: false })
    	}
    	if(!db.objectStoreNames.contains('doctor')) {
    		db.createObjectStore('doctor', { keyPath: 'id' });
    	}
    	if(!db.objectStoreNames.contains('developer')) {
    		db.createObjectStore('developer', { keyPath: 'id' });
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    删除对象库中的一条数据。

    语法:

    const res = store.delete(id)
    // id是keyPath值
    // 执行该方法后,会删除keyPath的值为id的那条数据。
    
    • 1
    • 2
    • 3

    示例:

    request.onsuccess = function() {
    	console.log('request: ', request.result);
    	db = this.result;
    	// 删
    	const transaction = db.transaction('teacher', 'readwrite');
    	const store = transaction.objectStore('teacher');
    	const res = store.delete(2); // 删除id为2的那条数据
    	res.onerror = function() {
    		console.log('add data error: ', res.error);
    	}
    	res.onsuccess = function() {
    		console.log('add data success...');
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    修改对象库中的某条数据。

    如果已经存在,就修改值;

    如果不存在,就添加到对象库中。

    注意,该方法是用于修改整条数据的内容,而不是修改数据中某个字段的值。

    如果需要修改某个字段的值,可以使用对象库遍历方法。

    语法:

    const res = store.put(data);
    res.onerror = function() {
        console.log('update data error: ', res.error);
    }
    res.onsuccess = function() {
        // result表示当前更新的数据的keyPath值
        console.log('update data success: ', res.result);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    示例:

    request.onsuccess = function() {
    	console.log('request: ', request.result);
    	db = this.result;
    	// 改
    	const transaction = db.transaction('teacher', 'readwrite');
    	const store = transaction.objectStore('teacher');
    	const res = store.put({id: 1, name: 'dilireba', age: 18});
    	res.onerror = function() {
    		console.log('put data error: ', res.error);
    	}
    	res.onsuccess = function() {
    		console.log('put data success...', res.result); // 1
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    查询某条对应keyPath值的数据。

    语法:

    // id是数据中的keyPath值
    const res = store.get(id);
    res.onerror = function() {
        console.log('find data error: ', res.error);
    }
    res.onsuccess = function() {
        // result是查询到的数据结果
        console.log('find data success: ', res.result);
    }
    // 需要注意的是,查询时,事务权限设置为'readonly'即可。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    示例:

    request.onsuccess = function() {
    	console.log('request: ', request.result);
    	db = this.result;
    	// 查
    	const transaction = db.transaction('teacher', 'readonly');
    	const store = transaction.objectStore('teacher');
    	const res = store.get(1); // 查id为1的那条数据
    	res.onerror = function() {
    		console.log('put data error: ', res.error);
    	}
    	res.onsuccess = function() {
    		console.log('put data success...', res.result);
            // {id: 1, name: 'dilireba', age: 18}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    清除

    清除某个对象库中的所有数据。

    语法:

    const res = store.clear();
    res.onerror = function() {
    	console.log('put data error: ', res.error);
    }
    res.onsuccess = function() {
    	console.log('put data success...');
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    示例:

    request.onsuccess = function() {
    	console.log('request: ', request.result);
    	db = this.result;
    	// 清除
    	const transaction = db.transaction('teacher', 'readwrite');
    	const store = transaction.objectStore('teacher');
    	const res = store.clear();
    	res.onerror = function() {
    		console.log('put data error: ', res.error);
    	}
    	res.onsuccess = function() {
    		console.log('put data success...');
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    条件查询

    根据条件查询到符合条件的所有数据。有三种语法。

    注意:事务的处理权限设置为readonly即可。

    语法一:查询某个对象库中的所有数据

    const res = store.getAll();
    res.onerror = function() {
        console.log('find all datas error: ', res.error);
    }
    res.onsuccess = function() {
        // result是所有数据组成的列表[...]
        console.log('find all datas success: ', res.result);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    示例:

    request.onsuccess = function() {
    	console.log('request: ', request.result);
    	db = this.result;
    	// 条件查询
    	const transaction = db.transaction('teacher', 'readonly');
    	const store = transaction.objectStore('teacher');
    	const res = store.getAll();
    	res.onerror = function() {
    		console.log('put data error: ', res.error);
    	}
    	res.onsuccess = function() {
    		console.log('put data success...: ', res.result);
            // [{id: 1, name: 'dilireba', age: 18},
            // {id: 2, name: 'zhaoliying', age: 19},
            // {id: 3, name: 'liuyifei', age: 20}]
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    语法二:查询某个对象库中所有符合query条件的数据。

    const res = store.getAll(query);
    res.onerror = function() {
        console.log('find all datas error: ', res.error);
    }
    res.onsuccess = function() {
        // result是返回的数据组成的列表[...]
        console.log('find all datas success: ', res.result);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    // 这里是query参数,是指符合IDBKeyRange筛选条件的一个范围。
    // 如果数据中的pathKey的值在这个范围内,就会作为数据返回。
    // 以下是query和范围的对应关系:
    
    • 1
    • 2
    • 3
    范围对应的代码,query
    All keys ≥ xIDBKeyRange.lowerBound(x)
    All keys > xIDBKeyRange.lowerBound(x, true)
    All keys ≤ yIDBKeyRange.upperBound(y)
    All keys < yIDBKeyRange.upperBound(y, true)
    All keys ≥ x && ≤ yIDBKeyRange.bound (x, y)
    All keys > x &&< yIDBKeyRange.bound (x, y, true, true)
    All keys > x && ≤ yIDBKeyRange.bound (x, y, true, false)
    All keys ≥ x &&< yIDBKeyRange.bound(x, y, false, true)
    The key = zIDBKeyRange.only (z)

    示例:

    request.onsuccess = function() {
    	db = this.result;
        // 数据中的id值大于等于2
    	const query = IDBKeyRange.lowerBound(2);
    	// 条件查询
    	const transaction = db.transaction('teacher', 'readonly');
    	const store = transaction.objectStore('teacher');
    	const res = store.getAll(query);
    	res.onerror = function() {
    		console.log('get data error: ', res.error);
    	}
    	res.onsuccess = function() {
    		console.log('get data success...: ', res.result);
            // [{id: 2, name: 'zhaoliying', age: 19},
            // {id: 3, name: 'liuyifei', age: 20}]
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    语法三:查询某个对象库中一定条数的符合query条件的数据。

    const res = store.getAll(query, count);
    res.onerror = function() {
        console.log('find all datas error: ', res.error);
    }
    res.onsuccess = function() {
        // result是返回的数据组成的列表[...]
        console.log('find all datas success: ', res.result);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    // count是要获取到的数据条数,必须是在0~2^32 - 1的范围内的数字,超出会报错。
    
    • 1

    示例:

    request.onsuccess = function() {
    	db = this.result;
    	const query = IDBKeyRange.lowerBound(2);
    	// 条件查询
    	const transaction = db.transaction('teacher', 'readonly');
    	const store = transaction.objectStore('teacher');
    	const res = store.getAll(query, 1); // 取符合条件的前1条数据
    	res.onerror = function() {
    		console.log('get data error: ', res.error);
    	}
    	res.onsuccess = function() {
    		console.log('get data success...: ', res.result);
            // [{id: 2, name: 'zhaoliying', age: 19}]
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    条件查询keyPath值

    语法也是有三条,参数同条件查询。

    // 语法一
    const res = store.getAllKeys();
    // 语法二
    const res = store.getAllKeys(query);
    // 语法三
    const res = store.getAllKeys(query, count);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    简单示例:

    request.onsuccess = function() {
    	db = this.result;
    	const transaction = db.transaction('teacher', 'readonly');
    	const store = transaction.objectStore('teacher');
    	const res = store.getAllKeys();
    	res.onerror = function() {
    		console.log('get keys error: ', res.error);
    	}
    	res.onsuccess = function() {
    		console.log('get keys success...: ', res.result);
            // 结果就是id值组成的列表[1, 2, 3] 
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    对象库中数据的条数

    查询某个对象库中有多少条数据。

    语法有两种。

    语法一:获取该对象库中共有多少条数据

    const res = store.count();
    res.onerror = function() {
        console.log('count data error: ', res.error);
    }
    res.onsuccess = function() {
        console.log('该对象库中一共有' + res.result + '条数据'.);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    示例:

    request.onsuccess = function() {
    	db = this.result;
    	const transaction = db.transaction('teacher', 'readonly');
    	const store = transaction.objectStore('teacher');
    	const res = store.count();
    	res.onerror = function() {
    		console.log('count data error: ', res.error);
    	}
    	res.onsuccess = function() {
    		console.log('count data success...: ', res.result); // 3
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    语法二:

    条件查询,符合某个条件的数据共有多少条。

    // 参数query仍然是符合IDBKeyRange筛选条件的一个范围。参考上表。
    const res = store.count(query);
    res.onerror = function() {
        console.log('count data error: ', res.error);
    }
    res.onsuccess = function() {
        console.log('该对象库中符合query条件的数据一共有' + res.result + '条'.);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    对象库遍历IDBCursor

    IDBCursor接口表示一个游标,用于遍历或迭代数据库中的多条记录。

    游标可以理解为下标或者指针,指示需要遍历哪一个索引或者对象存储区。

    语法

    1. store.openCursor

    该方法用于打开一个游标,开启遍历。

    它还可以有传递两个参数store.openCursor(query, direction)

    query表示要查询的键或者上面表格中的范围值。可选的。
    direction表示游标要移动的方向,有4个值:
    - next 默认值。表示下一个,键值从小到大一个个遍历,也就是正序遍历。
    - nextunique 正序遍历时,过滤掉重复项,会从重复项中选取较小的那个值。
    - prev 表示键值从大到小一个个遍历,也就是倒序遍历。
    - prevunique 倒序遍历时,过滤掉重复项。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    示例:

    request.onsuccess = function() {
    	db = this.result; // 这里是this指向request
    	const transaction = db.transaction('teacher', 'readwrite');
    	const store = transaction.objectStore('teacher');
    	const res = store.openCursor(); // 开启遍历
    	res.onerror = function() {
    		console.log('each data error: ', res.error);
    	}
    	res.onsuccess = function() { // 这里面的内容将被遍历执行
    		console.log('each data success...');
    		const cursor = this.result; // 这里的this指向res
    		if(cursor) {
    			console.log('val: ', cursor.value);
    			cursor.continue();
    		} else {
    			console.log('没有更多结果了...');
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    示例执行结果:

    each data success...
    val: {id: 1, name: 'dilireba', age: 18}
    each data success...
    val: {id: 2, name: 'haha', age: 19}
    each data success...
    val: {id: 3, name: 'liuyifei', age: 20}
    each data success...
    val: {id: 4, name: 'lilei', age: 21}
    each data success...
    val: {id: 5, name: 'hanmeimei', age: 22}
    each data success...
    val: {id: 6, name: 'lihua', age: 23}
    没有更多结果了...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    1. cursor.advance or cursor.continue

    该语句不能缺少,不然无法遍历数据。

    cursor.advance是表示每一步遍历,要跳过多少个下标
    必须填写一个大于0的整数作为参数。
    
    • 1
    • 2

    比如当前在teacher对象库中有如下6个数据:

    {id: 1, name: 'dilireba', age: 18},
    {id: 2, name: 'haha', age: 19}
    {id: 3, name: 'liuyifei', age: 20}
    {id: 4, name: 'lilei', age: 21}
    {id: 5, name: 'hanmeimei', age: 22}
    {id: 6, name: 'lihua', age: 23}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    advance设置不同的值,会得到不同的结果:

    // cursor.advance(1)
    // 每次移动一次下标
    {id: 1, name: 'dilireba', age: 18},
    {id: 2, name: 'haha', age: 19},
    {id: 3, name: 'liuyifei', age: 20},
    {id: 4, name: 'lilei', age: 21},
    {id: 5, name: 'hanmeimei', age: 22},
    {id: 6, name: 'lihua', age: 23}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    // cursor.advance(2) 
    // 每次移动2次下标,先遍历id 1, 移动两次,遍历到id 3,以此类推。
    {id: 1, name: 'dilireba', age: 18},
    {id: 3, name: 'liuyifei', age: 20},
    {id: 5, name: 'hanmeimei', age: 22}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    // cursor.advance(3)
    // 每次移动3次下标,先遍历id 1, 然后移动3次下标,遍历到id 4, 以此类推。
    {id: 1, name: 'dilireba', age: 18},
    {id: 4, name: 'lilei', age: 21}
    
    • 1
    • 2
    • 3
    • 4
    cursor.continue是表示挨个遍历。相当于cursor.advance(1)
    
    • 1

    3)cursor.delete()

    无参数。

    删除游标位置记录,而不改变游标的位置。可以简单理解为,

    用于删除对象库中的某些特定数据。

    假定仍然是上述示例中的6条数据,

    // 遍历时判断 当id为2时,执行delete操作,删除id为2的这条数据
    if(curcor) {
        if(curcor.value.id === 2) {
            curcor.delete(); // id为2的数据被删除
        }
    } else {
        console.log('没有更多的结果了...');
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4)cursor.update()

    更新对象库中当前游标位置的值,可以用于更改特定数据中的某个字段的值。

    示例:

    // 把id为2的数据中的name值改为'张三'
    if(curcor) {
        if(curcor.value.id === 2) {
            curcor.update({...curcor.value, name: '张三'});
        }
    } else {
        // ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    按照对象库的数据的keyPath进行遍历

    1)语法:

    const store = transaction.objectStore('teacher').index(indexKeyPath);
    
    • 1

    这里必须说说对象库的keyPath和对象库数据的keyPath,刚接触的时候可能造成混淆。


    2)为什么会出现不同的keyPath?

    一个对象库,比如teacher,里面的数据可能有很多个字段,比如id , name, age, sex, hobby等。

    { id: 1, name: 'dilireba', age: 18, sex: 0, hobby: 'sleep' }
    
    • 1

    id是对象库的keyPath,也就是说,我们在遍历对象库时,是根据id进行遍历的,

    但是实际应用中,我们还可能根据名字name进行遍历,也可能是根据年龄age进行遍历,

    为了解决这个问题,就出现了对象库的keyPath和对象库数据的keyPath


    3)怎么区分?

    示例:

    request.onupgradeneeded = function() {
    	console.log('open upgrade...');
    	db = this.result;
    	if(!db.objectStoreNames.contains('teacher')) {
    		const objectStore = db.createObjectStore('teacher', { keyPath: 'id' });
    		objectStore.createIndex('name', 'name', { unique: true });
    		objectStore.createIndex('age', 'age', { unique: false })
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在示例中,通过db.createObjectStore创建对象库并设置的keyPath就是对象库的keyPath

    也就是此处的id就是对象库teacherkeyPath,遍历对象库,都是根据id的值来遍历的。

    而示例中通过objectStore.createIndex创建的nameage,就是数据的keyPath

    在遍历对象库中的数据时,也可以通过nameage进行遍历。


    4)如何使用数据中的keyPath进行遍历?

    语法:

    const store = transaction.objectStore('teacher').index(indexKeyPath);
    
    • 1

    示例1:根据age进行遍历

    request.onsuccess = function() {
    	db = this.result; // 这里是this指向request
    	const transaction = db.transaction('teacher', 'readwrite');
        // index('age')
    	const store = transaction.objectStore('teacher').index('age');
    	const res = store.openCursor();
    	res.onerror = function() {
    		console.log('each data error: ', res.error);
    	}
    	res.onsuccess = function() {
    		console.log('each data success...');
    		const cursor = this.result; // 这里的this指向res
    		if(cursor) {
    			console.log('val: ', cursor.value);
    			cursor.continue();
    		} else {
    			console.log('没有更多结果了...');
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    示例结果:

    {id: 3, name: 'zhangsan', age: 16}
    {id: 1, name: 'dilireba', age: 18}
    {id: 4, name: 'lilei', age: 21}
    {id: 5, name: 'hanmeimei', age: 22}
    {id: 6, name: 'lihua', age: 23}
    {id: 2, name: 'liuyifei', age: 32}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    示例2:根据name进行遍历

    request.onsuccess = function() {
    	db = this.result; // 这里是this指向request
    	const transaction = db.transaction('teacher', 'readwrite');
        // index('name')
    	const store = transaction.objectStore('teacher').index('name');
    	const res = store.openCursor();
    	res.onerror = function() {
    		console.log('each data error: ', res.error);
    	}
    	res.onsuccess = function() {
    		console.log('each data success...');
    		const cursor = this.result; // 这里的this指向res
    		if(cursor) {
    			console.log('val: ', cursor.value);
    			cursor.continue();
    		} else {
    			console.log('没有更多结果了...');
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    示例结果:

    {id: 1, name: 'dilireba', age: 18}
    {id: 5, name: 'hanmeimei', age: 22}
    {id: 6, name: 'lihua', age: 23}
    {id: 4, name: 'lilei', age: 21}
    {id: 2, name: 'liuyifei', age: 32}
    {id: 3, name: 'zhangsan', age: 16}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    学习资料

    • MDN

      https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API
      
      • 1
    • IndexedDB阮一峰

      https://www.ruanyifeng.com/blog/2018/07/indexeddb.html
      
      • 1
  • 相关阅读:
    Java开发学习(四十三)----MyBatisPlus查询语句之查询投影
    Spring Cloud学习笔记(服务网关Zuul)
    Sklearn基本算法
    数学建模 Matlab Simulink
    生成数字图像基本过程
    记录ElasticSearch分片被锁定导致无法分配处理过程
    C/C++:指针用法详解
    网络流量安全分析-工作组异常
    [Java反序列化]—CommonsCollections5
    【语音去噪】基于切比雪夫+椭圆形低通滤波器语音去噪附GUI界面
  • 原文地址:https://blog.csdn.net/tuzi007a/article/details/127979843