indexedDB
2022/12/24 4:24:00
本文主要是介绍indexedDB,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
-
背景
为了实现客户端缓存,虽然已经有很多技术被不断推出和应用,但是随着浏览器功能的不断增强和完善,现有的缓存技术,其局限性也变得越来越明显:
- 容量太小: cookie和Web Storage最多也就支持5M,已经不能满足需求了
- 检索不方便: cookie和Web Storage都是以字符串形式存储数据,复杂对象数据存取前需要做处理,比较麻烦
- 其它问题:不能提供搜索功能,不能建立自定义的索引
这些就是 IndexedDB(Indexed DataBase)诞生的背景,从字面上可以看出,这就是浏览器提供的本地数据库。IndexedDB可以被网页脚本创建和操作。IndexedDB 允许储存大量数据,提供查找接口,还能建立索引。这些都是 Web Storage 所不具备的。
-
特点
- 键值对储存: IndexedDB 内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 JavaScript 对象。对象仓库中,数据以"键值对"的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。
- 异步: IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage 形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。
- 支持事务: IndexedDB 支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。
- 同源限制: IndexedDB 受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。
- 储存空间大: IndexedDB 的储存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有上限。
- 支持二进制储存: IndexedDB 不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer 对象和 Blob 对象)。
-
使用
- 创建数据库
// 创建或打开数据库 const myDB = window.indexedDB.open('myDB', 1); // 数据库连接成功 myDB.addEventListener('success', e => { console.log("数据库连接成功~"); }); // 数据库连接失败 myDB.addEventListener('error', e => { console.log("数据库连接失败~"); });
- 创建对象仓库
对象仓库(Object Store)是 indexedDB 数据库的基础,熟悉数据库的朋友都知道数据库表的含义,这个对象仓库(以下统一简称仓库)其实就类似于数据库中表的概念。
const myDB = indexedDB.open('myDB', 2); myDB.addEventListener('upgradeneeded', e => { const dbResult = e.target.result; // 创建一个"用户信息"仓库 UserInfo const createdStore = dbResult.createObjectStore( 'UserInfo', { keyPath: 'id', autoIncrement: false } ); });
- 创建事务
-
原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。(原子性的意思是每次操作都可以是最小单元,即是可回退也可执行)
-
一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。
-
隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
-
持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中。
const myDB = indexedDB.open('myDB', 3); myDB.addEventListener('success', e => { const dbResult = e.target.result; const dbTrans = dbResult.transaction('UserInfo', 'readwrite'); });
- 数据操作
在数据操作前首先是获取事务对象,通过事务对象的objectStore()方法获取具体的仓库
// 打开数据库,获取dbResult对象 // ... // 创建事务 const dbTrans = dbResult.transaction(['UserInfo'], 'readwrite'); // 获取仓库 const dbStore = dbTrans.objectStore('UserInfo'); // 后续其他操作 // ...
- 新增数据: 即往仓库中添加一条新数据
// 使用add()方法,参数为一条数据对象 const dbRequest = dbStore.add({ id: 1, name: '张三', age: 20, email: 'zhangsan@example.com' }); dbRequest.onsuccess = e => { console.log('数据添加成功~'); }; dbRequest.onerror = e => { console.log('数据添加失败~'); };
- 查找数据: 即查找数据仓库中某一条数据
// 使用get()方法,参数为主键的值,即示例中id==1的数据 const dbRequest = dbStore.get(1); dbRequest.onsuccess = e => { const { result } = dbRequest; if (result) { const { name, age, email } = result; console.log('name:', name); console.log('age:', age); console.log('email:', email); } else { console.log('未查到对应数据'); } }; dbRequest.onerror = e => { console.log('数据查询失败~'); };
- 遍历数据 即遍历数据表格的一批记录,要使用指针(又称游标)对象IDBCursor。
const myDB = indexedDB.open('myDB', 4); myDB.addEventListener('success', e => { const dbResult = e.target.result; const dbTrans = dbResult.transaction('UserInfo'); const dbStore = dbTrans.objectStore('UserInfo'); const boundRange = IDBKeyRange.bound(1,5); const dbRequest = dbStore.openCursor(boundRange, 'next'); dbRequest.onsuccess = e => { const dbCursor = dbRequest.result || e.target.result; if (dbCursor){ const { key, value } = dbCursor; console.log('id:', key); console.log('name:', value.name); console.log('age:', value.age); console.log('email:', value.email); dbCursor.continue(); } else { console.log('编辑完毕~'); } }; });
- 删除数据 即删除仓库中的某一条数据
// 使用delete()方法,参数为主键的值 const dbRequest = dbStore.delete(1); dbRequest.onsuccess = e => { console.log('数据删除成功~'); }; dbRequest.onerror = e => { console.log('数据删除失败~'); };
- 更新数据 即修改仓库中的某一条数据
// 使用put()方法,参数为一条数据对象 const dbRequest = dbStore.put({ id: 1, name: '李四', age: 22, email: 'lisi@example.com' }); dbRequest.onsuccess = e => { console.log('数据更新成功~'); }; dbRequest.onerror = e => { console.log('数据更新失败~'); };
- 索引查询数据
const myDB = indexedDB.open('myDB', 5); myDB.addEventListener('upgradeneeded', e => { const dbResult = e.target.result; // 创建一个"用户信息"仓库 UserInfo const createdStore = dbResult.createObjectStore( 'UserInfo', { keyPath: 'id', autoIncrement: false } ); // 创建索引,索引值为ageIndex,对应的键名(或称属性)为age createdStore.createIndex( 'ageIndex', 'age', { unique: false } ); });
createIndex(indexName, pathKey, options)方法接收三个参数:
indexName: 要创建的索引名,该值唯一,不可重复
pathKey: 仓库里需要建立索引的目标键名(key),或者多个键名组成的数组
options: 是一个可选的配置参数对象,有unique和multiEntry两个值
unique: 用来指定索引值是否可以重复,为true代表不能相同,为false时代表可以相同
multiEntry: 当第二个参数keyPath为一个数组时,如果multiEntry是true,则会以数组中的每个元素建立一条索引,如果是false,则以整个数组为keyPath值,添加一条索引.
const myDB = indexedDB.open('myDB', 4); myDB.addEventListener('success', e => { const dbResult = e.target.result; const dbTrans = dbResult.transaction('UserInfo'); const dbStore = dbTrans.objectStore('UserInfo'); const lowerBound = IDBKeyRange.lowerBound(20); const indexStore = dbStore.index('ageIndex'); const dbRequest = indexStore.openCursor(lowerBound, 'next'); dbRequest.addEventListener('success', e => { const dbCursor = e.target.result; if (dbCursor) { const { key, value } = dbCursor; console.log('id:', key); console.log('name:', value.name); console.log('age:', value.age); console.log('email:', value.email); dbCursor.continue(); } else { console.log('编辑完毕~'); } }) });
这篇关于indexedDB的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-05-01为什么公共事业机构会偏爱 TiDB :TiDB 数据库在某省妇幼健康管理系统的应用
- 2024-04-26敏捷开发:想要快速交付就必须舍弃产品质量?
- 2024-04-26静态代码分析的这些好处,我竟然都不知道?
- 2024-04-26你在测试金字塔的哪一层?(下)
- 2024-04-26快刀斩乱麻,DevOps让代码评审也自动起来
- 2024-04-262024年最好用的10款ER图神器!
- 2024-04-2203-为啥大模型LLM还没能完全替代你?
- 2024-04-2101-大语言模型发展
- 2024-04-17基于SpringWeb MultipartFile文件上传、下载功能
- 2024-04-14个人开发者,Spring Boot 项目如何部署