客户端持久化数据库---indexedDB使用
_
阅读目录
- 一:什么是indexedDB数据库?
- 二:IndexedDB数据库操作
一:什么是indexedDB数据库?
indexedDB是浏览器中的事务类型对象存储数据库。indexedDB适合大量的结构的数据存储。
适用场景:当数据量不是很大的时候,我们可以使用sessionStorage或LocalStorage来进行存储,但是当数据量非常大的时候,我们需要使用本地数据库来存储,因此这个时候 indexedDB 浏览器数据库应运而生。
indexedDB 有如下特点:
1)异步的;indexedDB打开数据库或获取数据的时候都是异步的,也就是说它不会堵塞浏览器操作。异步就是为了防止大量数据的读写操作,防止网页变慢或卡顿。
2)键值对存储。indexedDB内部采用对象仓库(object store) 来存放数据的,所有类型的数据都可以直接存储。在对象仓库中,
数据以 "键值对" 的形式保存,每一个数据记录都有对应的主键,主键是不可重复的。
3)支持事务型的。indexedDB执行的操作会按照事务来分组的,在一个事务中,要么所有的操作都成功,要么所有的操作都失败。
4)同源限制。indexedDB有同源限制,每一个数据库只能在自身域名下能访问,不能跨域名访问。
5)存储空间大。存储空间可以达到几百兆甚至更多。
6)支持二进制存储。它不仅可以存储字符串,而且还可以存储二进制数据(ArrayBuffer对象或Blob对象)。
2.1 打开或创建数据库
使用indexedDB的第一步是打开我们的数据库,使用 indexedDB.open()方法,如下所示:
<!DOCTYPE html>
<html>
<head>
<title>indexedDB数据库使用</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
</head>
<body>
<script type="text/javascript">
var request = window.indexedDB.open('my-database', 1);
console.log(request);
</script>
</body>
</html>
打印 如上的 信息,如下所示:

该方法接收2个参数,第一个参数是字符串,表示数据库的名字。如果指定的数据库不存在的话,就会新建该数据库。第二个参数是一个整数,它表示的是数据库的版本。如果省略第二个参数的话,如果是新建数据库的话,默认为1. 如果是打开已有的数据库的话,默认就为当前的版本。
数据库被创建完成后,我们可以打开我们的控制台 -> application -> indexedDB 下 就有 我们刚刚的 my-database 数据库了,如下所示:
从上面打印的信息我们可以看到,创建一个数据库完成后,该实列有 onerror, onsuccess, onupgradeneeded 监听函数。及 result 属性值。
indexedDB.open() 方法返回的是一个IDBRequest对象,代表一个请求连接数据库的请求对象。该对象通过三种事件:onerror、onsuccess、onupgradeneeded 处理打开数据库的操作结果的。我们可以通过监听请求对象的 onsuccess 和 onerror 事件来定义连接成功或失败需要执行的方法。如下代码:
var request = window.indexedDB.open('my-database');
var db;
request.onerror = function() {
console.log('数据库打开报错');
}
request.onsuccess = function(event) {
console.log(event.target);
db = request.result;
console.log('数据库打开成功');
}
request.onupgradeneeded = function(event) {
console.log('数据库升级事件');
console.log(event.target);
db = event.target.result;
}
如上代码执行的结果如下:

如上我们可以看到,会执行我们的 onsuccess的方法,但是 onupgradeneeded 是不会执行的,该监听函数只监听当当前的版本号升级的时候才会被触发,也就是说,数据库的版本号更改为大于当前的数据库的版本才会被执行。
注意:从上面我们也可以看到 event.target === request 实列对象.
当我们现在把数据库的版本号升级到2的时候,之前的版本号是1,现在数据库的版本升级了,就会触发 onupgradeneeded 事件,如下代码所示:
var request = window.indexedDB.open('my-database', 2);
var db;
request.onupgradeneeded = function(event) {
console.log('数据库升级事件');
console.log(event.target);
db = event.target.result;
}
实现效果如下所示:

2.2 创建对象仓库(或叫创建表)
如上我们的indexedDB数据库新建完成后,我们现在要做的事情就行新建表格了。不过在indexedDB中没有数据库表,而叫对象仓库,不过它的作用就相当于一个数据库表。它使用的 createObjectStore 来创建的,如下代码演示:
var request = window.indexedDB.open('my-database', 3);
var db;
request.onupgradeneeded = function(event) {
db = event.target.result;
var store;
if (!db.objectStoreNames.contains('Users')) {
store = db.createObjectStore('Users', {keyPath: 'id', autoIncrement: true });
}
console.log('创建对象仓库成功');
console.log(store);
}
如上代码,db.createObjectStore 方法接收2个参数,第一个为对象的仓库名(也可以理解我们之前的数据库表名),第二个参数为可选参数,值为一个js对象,该对象中的 keyPath属性为主键,autoIncrement 属性为 true,表示主键值自增。
db.objectStoreNames.contains('Users') 的含义:是否包含该对象仓库名(或叫表名)。如果不包含就创建一个。
2.3 创建索引
在indexedDB中,我们使用 createIndex 来创建它的索引。通过数据对象的某个属性来创建索引,在数据库中进行检索数据的时候,我们只能通过被设置为索引的属性来进行检索的。
如下代码:
var request = window.indexedDB.open('my-database', 4);
var db;
request.onupgradeneeded = function(event) {
db = event.target.result;
var store;
if (!db.objectStoreNames.contains('newUsers')) {
store = db.createObjectStore('newUsers', {keyPath: 'id', autoIncrement: true });
}
console.log(store);
// 创建索引
store.createIndex('userIndex', 'userName', { unique: false });
store.createIndex('userEmail', 'email', { unique: true });
console.log('创建索引成功');
}
如上代码:store.createIndex 方法接收三个参数,第一个为索引名,第二个为数据对象的属性,第三个参数是可选参数,值为一个js对象,该对象中的 unique 属性值为true,代表该索引值是唯一的,不可以相同的。如果为false的话,则可以相同。
索引创建完成后,我们需要事务操作了。
2.4 新增数据
在indexedDB中,我们能够使用事务来进行数据库的操作,事务有三个模式。
1. readOnly: 只读
2. readwrite: 可读可写
3. versionchange: 数据库版本变化
我们创建一个事务时,需要选择一种模式,如果不指定的话,则默认为只读模式。比如代码如下:
var transaction = db.transaction(['customers'], 'readwrite');
创建事务我们使用 db.transaction方法。该方法接收2个参数,第一个参数是字符串或数组,字符串是一个对象的仓库名。数组则是由对象仓库名组成的数组。第二个参数是事务模式。比如上面的模式是只读,或 可读可写。
新增数据指的是向对象仓库写入数据记录,这需要通过事务完成。该方法接收一个参数,保存到对象仓库中的对象。
如下代码所示:
var request = window.indexedDB.open('my-database', 4);
var db;
request.onupgradeneeded = function(event) {
db = event.target.result;
var store;
if (!db.objectStoreNames.contains('newUsers')) {
store = db.createObjectStore('newUsers', {keyPath: 'id', autoIncrement: true });
}
console.log(store);
// 创建索引
store.createIndex('userIndex', 'userName', { unique: false });
store.createIndex('userEmail', 'email', { unique: true });
console.log('创建索引成功');
}
request.onsuccess = function(event) {
db = event.target.result;
var transaction = db.transaction(['newUsers'], 'readwrite');
var objStore = transaction.objectStore('newUsers');
objStore.add({name: 'a', age: 10});
objStore.add({name: 'b', age: 20});
}
如上代码,我们使用 var transaction = db.transaction(['newUsers'], 'readwrite'); 代码来创建一个事务,第一个参数 'newUsers' 是对象仓库名,是我们之前在 onupgradeneeded 函数里面创建仓库的。事务新建以后,我们使用 transaction.objectStore('newUsers') 这个方法,拿到 IDBObjectStore 对象,再通过表格对象的add()方法,向表格写入一条记录。如下所示:

2.5 读取数据
读取数据也是通过事务完成的。如下代码:
var request = window.indexedDB.open('my-database', 4);
var db;
request.onsuccess = function(event) {
db = event.target.result;
var transaction = db.transaction(['newUsers'], 'readwrite');
var objStore = transaction.objectStore('newUsers');
// 读取数据
var req = objStore.get(1);
req.onsuccess = function(e) {
if (req.result) {
console.log('已经查询到数据为:');
console.log(req.result);
} else {
console.log('未查询到数据');
}
}
}
如上面代码中,objStore.get()方法用于读取数据,参数是主键的值。比如我们来查看下我们的主键key在我们的Application下有如下key值;

如上我们获取的key = 1;因此打印的效果如下所示:

2.6 遍历数据
如果我们需要遍历整个存储空间的数据时,我们就需要使用流标,流标通过对象仓库的 openCursor方法创建打开,该方法可以传递2个参数,第一个参数是 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); /*
lowerRange 表示大于等于1的主键值的集合。
第二个参数可选,为true表示不包含最小主键1,默认为false
*/
var lowerRange = IDBKeyRange.lowerBound(1, false); /*
upperRange 表示小于等于10的主键值的集合。
第二个参数可选,为true则表示不包含最大主键10,false则包含,默认为false
*/
var upperRange = IDBKeyRange.upperBound(10, false);
openCursor方法 的第二个参数表示流标的读取方向,主要有以下几种:
next: 流标中的数据按主键值升序排序,主键值相等的数据都被读取到。
nextunique: 流标中的数据按主键值升序排序,主键值相等只读取第一条数据。
prev: 流标中的数据按主键值降序排序,主键值相等的数据都被读取。
prevunique: 流标中的数据按主键值降序排序,主键值相等只读取第一条数据。
如果不使用参数的话,则是查询所有的记录,使用方法代码如下所示:
var request = window.indexedDB.open('my-database', 4);
var db;
var datas = [];
request.onsuccess = function(event) {
db = event.target.result;
var transaction = db.transaction(['newUsers'], 'readwrite');
var objStore = transaction.objectStore('newUsers');
// 使用流标 openCursor
objStore.openCursor().onsuccess = function(e) {
var cursor = e.target.result;
if (cursor) {
console.log(cursor);
datas.push(cursor);
cursor.continue();
} else {
console.log('没有数据了');
console.log(datas);
}
}
}
打印 cursor 信息如下所示:

下面我们使用 openCursor中两个参数来看下demo,如下所示代码:
var request = window.indexedDB.open('my-database', 6);
var db;
var datas = [];
request.onsuccess = function(event) {
console.log(IDBKeyRange)
console.log(111);
db = event.target.result;
var transaction = db.transaction(['newUsers'], 'readwrite');
var objStore = transaction.objectStore('newUsers');
var range = IDBKeyRange.bound(2, 10);
// 使用流标 openCursor
console.log(222);
objStore.openCursor(range, 'next').onsuccess = function(e) {
var cursor = e.target.result;
if (cursor) {
console.log(cursor);
datas.push(cursor);
cursor.continue();
} else {
console.log('没有数据了');
console.log(datas);
}
}
}
如上 IDBKeyRange.bound(2, 10)方法的含义是:表示主键从2到10的集合. objStore.openCursor(range, 'next') 的含义是:流标中的数据按主键值升序排序,主键值相等的数据都被读取到。我们首先来看下我们的 my-database 数据库中 newUsers表中的数据如下:

可以看到如上面我们的id就是我们的主键。然后我们如上运行结果如下所示:

更多的相关IDBKeyRange的API请看官网
2.7 更新数据
更新数据我们需要使用 IDBObject.put() 方法。该方法也是接收一个参数,为需要保存到对象仓库中的对象。
var request = window.indexedDB.open('my-database', 4);
var db;
request.onsuccess = function(event) {
console.log(IDBKeyRange)
console.log(111);
db = event.target.result;
var transaction = db.transaction(['newUsers'], 'readwrite');
var objStore = transaction.objectStore('newUsers');
var newValue = {
'name': 'kongzhi',
'age': '30',
'id': 1
};
// 更新数据
var req1 = objStore.put(newValue);
// 获取主键为1的数据
var req2 = objStore.get(1);
// 加载主键为1的数据
req2.onsuccess = function(e) {
var cursor = e.target.result;
if (cursor) {
console.log(cursor);
} else {
console.log('没有数据了');
}
}
}
如上代码,我们使用 objStore.put(newValue); 这个方法去更新主键为1的数据,然后使用 objStore.get(1) 方法来获取主键为1的数据,最后监听 success 方法函数,成功后获取数据,打印信息如下图所示:
然后我们继续来看下 我们的控制台 -> application 下的 newUsers中的数据被更新成如下:

2.8 删除数据
我们使用 IDBObjectStore.delete() 方法用于删除记录。代码如下所示:
var request = window.indexedDB.open('my-database', 4);
var db;
request.onsuccess = function(event) {
console.log(IDBKeyRange)
console.log(111);
db = event.target.result;
var transaction = db.transaction(['newUsers'], 'readwrite');
var objStore = transaction.objectStore('newUsers');
// 删除主键为1的数据
var res = objStore.delete(1);
// 加载主键为1的数据
res.onsuccess = function(e) {
console.log('删除成功了');
}
}
如上代码,我们使用 objStore.delete(1) 方法删除主键为1的代码,然后在控制台中我们看到会打印 删除成功的 文案,然后我们到 我们的 application 再看看如下所示:

如上我们可以看到,我们的主键为1的记录没有了。
2.9 使用索引
索引的作用就是可以让我们搜索任意字段,我们可以根据索引来搜索任何一条记录,有索引使我们搜索的速度更快,就好比我们的一本书目录一样,它也有
对应的索引含义,我们可以根据该索引能快速查找到我们这一本书上的某一个知识点在第几页。在这里我们默认是按照主键来搜索。
如上创建索引那块的地方,我们可以看到使用如下语法创建索引:
store.createIndex('userIndex', 'userName', { unique: false });
我们首先来看下我们 索引userIndex 有如下值:如下所示:

现在我们使用普通的流标的方法来获取索引,代码如下所示:
var request = window.indexedDB.open('my-database', 6);
var db;
var datas = [];
request.onupgradeneeded = function(event) {
db = event.target.result;
var store;
if (!db.objectStoreNames.contains('newUsers2')) {
store = db.createObjectStore('newUsers2', {keyPath: 'id', autoIncrement: true });
console.log(store);
// 创建索引
store.createIndex('userIndex', 'userName', { unique: false });
console.log('创建索引成功1111');
}
}
request.onsuccess = function(event) {
db = event.target.result;
var transaction = db.transaction(['newUsers2'], 'readwrite');
var objStore = transaction.objectStore('newUsers2');
var req = objStore.index('userIndex').openCursor();
req.onsuccess = function(e) {
var res = e.target.result;
if (res) {
console.log(res);
datas.push(res);
res.continue();
} else {
console.log('没有数据了');
console.log(datas);
}
}
}
然后我们在onsuccess函数内部使用 datas数组,往数组里面添加一条数据,然后使用 res.continue(); 继续调用,因此多条数据都会被添加到 datas 数组里面去了,如下所示:

2.10 清空所有的数据 clear() 方法
我们现在来清空下 newUsers 仓库里面的数据,我们没有调用 clear() 方法清空之前,我们来看下 newUsers 表中有哪些数据,如下所示:

现在我们看如下代码,就可以清空 newUsers 仓库中所有的数据了,如下代码所示:
var request = window.indexedDB.open('my-database', 6);
var db;
var datas = [];
request.onsuccess = function(event) {
console.log(IDBKeyRange)
console.log(111);
db = event.target.result;
var transaction = db.transaction(['newUsers'], 'readwrite');
var objStore = transaction.objectStore('newUsers');
objStore.clear();
objStore.onsuccess = function(e) {
var res = e.target.result;
console.log(res);
}
}
然后我们继续来查看下我们的 Application 下的数据如下所示:

可以看到我们所有的数据都被清空了。
客户端持久化数据库---indexedDB使用的更多相关文章
- 客户端持久化解决方案:indexedDB
客户端持久化解决方案:indexedDB indexedDB适合大量的结构化的数据存储:打开数据库和获取数据对象都是异步的: 需要开启事务,访问的objectStore都要是在开启的事务中. 数据库结 ...
- 客户端持久化解决方案: Web SQL
客户端持久化解决方案: Web SQL Web SQL 提供了一组使用 SQL 操作客户端数据库的 APIs, 不是 HTML5 规范的一部分,是一个独立的规范. 核心方法 openDatabase: ...
- Android客户端与数据库交互数据的简单学习
Ø 数据库整理方案如下: 一.Android+ webservices+SQLServer : 通过webservices客户端向指定服务器发送请求,服务器响应返回指定格式的数据,如json或者x ...
- quartz 持久化 数据库表
此处只包括配置数据库操作 quartz 持久化数据库表格字段解释建表,SQL语句在dbTables文件夹中可以找到,介绍下我们开发主要使用到的表: (版本不一样,可能数据库表也不一样,这里使用2.2. ...
- 浏览器本地数据库 IndexedDB 基础详解
一.概述 随着浏览器的功能不断增强,越来越多的网站开始考虑,将大量数据储存在客户端,这样可以减少从服务器获取数据,直接从本地获取数据. 现有的浏览器数据储存方案,都不适合储存大量数据:Cookie 的 ...
- web API简介(四):客户端储存之IndexedDB API
概述 前篇:web API简介(三):客户端储存之Web Storage API 客户端储存从某一方面来说和动态网站差不多.动态网站是用服务端来储存数据,而客户端储存是用客户端来储存数据. Index ...
- 浏览器数据库 IndexedDB 入门
一.概述 随着浏览器的功能不断增强,越来越多的网站开始考虑,将大量数据储存在客户端,这样可以减少从服务器获取数据,直接从本地获取数据. 现有的浏览器数据储存方案,都不适合储存大量数据:Cookie 的 ...
- 浏览器数据库 IndexedDB 入门教程
一.概述 随着浏览器的功能不断增强,越来越多的网站开始考虑,将大量数据储存在客户端,这样可以减少从服务器获取数据,直接从本地获取数据. 现有的浏览器数据储存方案,都不适合储存大量数据:Cookie 的 ...
- html5本地存储(三)--- 本地数据库 indexedDB
html5内置了2种本地数据库,一是被称为“SQLLite”,可以通过SQL语言来访问文件型SQL数据库.二是被称为“indexedDB” 的NoSQL类型的数据库,本篇主要讲indexedDB数据库 ...
随机推荐
- 读BeautifulSoup官方文档之与bs有关的对象和属性(1)
自从10号又是5天没更, 是, 我再一次断更... 原因是朋友在搞python, 老问我问题, 我python也是很久没碰了, 于是为了解决他的问题, 我只能重新开始研究python, 为了快速找回感 ...
- C++杂记:运行时类型识别(RTTI)与动态类型转换原理
运行时类型识别(RTTI)的引入有三个作用: 配合typeid操作符的实现: 实现异常处理中catch的匹配过程: 实现动态类型转换dynamic_cast. 1. typeid操作符的实现 1.1. ...
- Quora的技术探索
关于问答类的应用,最早接触的是stackoverflow和知乎 ,而Quora作为知乎的原型,因为其创始人来自FaceBook而吸引了我.事实上关于Quora的技术分析,冯大辉和陈皓都已经有所详细的阐 ...
- C#匹配中文字符串的4种正则表达式分享
本文介绍在C#中使用匹配中文的正则表达式,包括纯中文.有中文.中文开头.中文结尾等几个正则表达式示例.在正则表达式中,中文可以通过Unicode编码来确定正则表达式范围. 在C#中,匹配中文的正则表达 ...
- C#图片保存与读取,以及图片另存
照片的保存与读取 /// <summary> /// 图片转二进制 /// </summary> /// <param name="imgPhoto" ...
- NET C#创建WINDOWS系统用户
原文:NET C#创建WINDOWS系统用户 /前提是当前用户有相应的权限 /WinNT用户管理 using System; using System.DirectoryServices; na ...
- C语言实现的CRC16/CCITT-FALSE校验码函数
要求:输入字符串“00 AA FF CC AA 01 00” 得到校验码“79B1” 方法1: // ConsoleApplication1.cpp: 定义控制台应用程序的入口点. // #inclu ...
- UWP-消息提示(仿Android)
原文:UWP-消息提示(仿Android) 在UWP中的消息提示框(一)中介绍了一些常见的需要用户主动去干涉的一些消息提示框,接下来打算聊聊不需要用户主动去干涉的一些消息提示框.效果就是像双击退出的那 ...
- ML:吴恩达 机器学习 课程笔记(Week5~6)
Neural Networks: Learning Advice for Applying Machine Learning Machine Learning System Design
- 代理Delegate的小应用(使用setModelData设置下拉日期对话框)
前言 在平时关于表格一类的的控件使用中,不可避免需要修改每个Item的值,通过在Item中嵌入不同的控件对编辑的内容进行限定,然而在表格的Item中插入的控件始终显示,当表格中item项很多的时候,会 ...