浏览器数据库 IndexedDB 入门教程
一、概述
随着浏览器的功能不断增强,越来越多的网站开始考虑,将大量数据储存在客户端,这样可以减少从服务器获取数据,直接从本地获取数据。
现有的浏览器数据储存方案,都不适合储存大量数据:Cookie 的大小不超过4KB,且每次请求都会发送回服务器;LocalStorage 在 2.5MB 到 10MB 之间(各家浏览器不同),而且不提供搜索功能,不能建立自定义的索引。所以,需要一种新的解决方案,这就是 IndexedDB 诞生的背景。
通俗地说,IndexedDB 就是浏览器提供的本地数据库,它可以被网页脚本创建和操作。IndexedDB 允许储存大量数据,提供查找接口,还能建立索引。这些都是 LocalStorage 所不具备的。就数据库类型而言,IndexedDB 不属于关系型数据库(不支持 SQL 查询语句),更接近 NoSQL 数据库。
IndexedDB 具有以下特点。
(1)键值对储存。 IndexedDB 内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 JavaScript 对象。对象仓库中,数据以"键值对"的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。
(2)异步。 IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage 形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。
(3)支持事务。 IndexedDB 支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。
(4)同源限制 IndexedDB 受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。
(5)储存空间大 IndexedDB 的储存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有上限。
(6)支持二进制储存。 IndexedDB 不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer 对象和 Blob 对象)。
二、基本概念
IndexedDB 是一个比较复杂的 API,涉及不少概念。它把不同的实体,抽象成一个个对象接口。学习这个 API,就是学习它的各种对象接口。
- 数据库:IDBDatabase 对象
- 对象仓库:IDBObjectStore 对象
- 索引: IDBIndex 对象
- 事务: IDBTransaction 对象
- 操作请求:IDBRequest 对象
- 指针: IDBCursor 对象
- 主键集合:IDBKeyRange 对象
下面是一些主要的概念。
(1)数据库
数据库是一系列相关数据的容器。每个域名(严格的说,是协议 + 域名 + 端口)都可以新建任意多个数据库。
IndexedDB 数据库有版本的概念。同一个时刻,只能有一个版本的数据库存在。如果要修改数据库结构(新增或删除表、索引或者主键),只能通过升级数据库版本完成。
(2)对象仓库
每个数据库包含若干个对象仓库(object store)。它类似于关系型数据库的表格。
(3)数据记录
对象仓库保存的是数据记录。每条记录类似于关系型数据库的行,但是只有主键和数据体两部分。主键用来建立默认的索引,必须是不同的,否则会报错。主键可以是数据记录里面的一个属性,也可以指定为一个递增的整数编号。
{ id: 1, text: 'foo' }
上面的对象中,id
属性可以当作主键。
数据体可以是任意数据类型,不限于对象。
(4)索引
为了加速数据的检索,可以在对象仓库里面,为不同的属性建立索引。
(5)事务
数据记录的读写和删改,都要通过事务完成。事务对象提供error
、abort
和complete
三个事件,用来监听操作结果。
三、操作流程
IndexedDB 数据库的各种操作,一般是按照下面的流程进行的。这个部分只给出简单的代码示例,用于快速上手,详细的各个对象的 API 请看这里。
3.1 打开数据库
使用 IndexedDB 的第一步是打开数据库,使用indexedDB.open()
方法。
var request = window.indexedDB.open(databaseName, version);
这个方法接受两个参数,第一个参数是字符串,表示数据库的名字。如果指定的数据库不存在,就会新建数据库。第二个参数是整数,表示数据库的版本。如果省略,打开已有数据库时,默认为当前版本;新建数据库时,默认为1
。
indexedDB.open()
方法返回一个 IDBRequest 对象。这个对象通过三种事件error
、success
、upgradeneeded
,处理打开数据库的操作结果。
(1)error 事件
error
事件表示打开数据库失败。
request.onerror = function (event) {
console.log('数据库打开报错');
};
(2)success 事件
success
事件表示成功打开数据库。
var db; request.onsuccess = function (event) {
db = request.result;
console.log('数据库打开成功');
};
这时,通过request
对象的result
属性拿到数据库对象。
(3)upgradeneeded 事件
如果指定的版本号,大于数据库的实际版本号,就会发生数据库升级事件upgradeneeded
。
var db; request.onupgradeneeded = function (event) {
db = event.target.result;
}
这时通过事件对象的target.result
属性,拿到数据库实例。
3.2 新建数据库
新建数据库与打开数据库是同一个操作。如果指定的数据库不存在,就会新建。不同之处在于,后续的操作主要在upgradeneeded
事件的监听函数里面完成,因为这时版本从无到有,所以会触发这个事件。
通常,新建数据库以后,第一件事是新建对象仓库(即新建表)。
request.onupgradeneeded = function(event) {
db = event.target.result;
var objectStore = db.createObjectStore('person', { keyPath: 'id' });
}
上面代码中,数据库新建成功以后,新增一张叫做person
的表格,主键是id
。
更好的写法是先判断一下,这张表格是否存在,如果不存在再新建。
request.onupgradeneeded = function (event) {
db = event.target.result;
var objectStore;
if (!db.objectStoreNames.contains('person')) {
objectStore = db.createObjectStore('person', { keyPath: 'id' });
}
}
主键(key)是默认建立索引的属性。比如,数据记录是{ id: 1, name: '张三' }
,那么id
属性可以作为主键。主键也可以指定为下一层对象的属性,比如{ foo: { bar: 'baz' } }
的foo.bar
也可以指定为主键。
如果数据记录里面没有合适作为主键的属性,那么可以让 IndexedDB 自动生成主键。
var objectStore = db.createObjectStore(
'person',
{ autoIncrement: true }
);
上面代码中,指定主键为一个递增的整数。
新建对象仓库以后,下一步可以新建索引。
request.onupgradeneeded = function(event) {
db = event.target.result;
var objectStore = db.createObjectStore('person', { keyPath: 'id' });
objectStore.createIndex('name', 'name', { unique: false });
objectStore.createIndex('email', 'email', { unique: true });
}
上面代码中,IDBObject.createIndex()
的三个参数分别为索引名称、索引所在的属性、配置对象(说明该属性是否包含重复的值)。
3.3 新增数据
新增数据指的是向对象仓库写入数据记录。这需要通过事务完成。
function add() {
var request = db.transaction(['person'], 'readwrite')
.objectStore('person')
.add({ id: 1, name: '张三', age: 24, email: 'zhangsan@example.com' }); request.onsuccess = function (event) {
console.log('数据写入成功');
}; request.onerror = function (event) {
console.log('数据写入失败');
}
} add();
上面代码中,写入数据需要新建一个事务。新建时必须指定表格名称和操作模式("只读"或"读写")。新建事务以后,通过IDBTransaction.objectStore(name)
方法,拿到 IDBObjectStore 对象,再通过表格对象的add()
方法,向表格写入一条记录。
写入操作是一个异步操作,通过监听连接对象的success
事件和error
事件,了解是否写入成功。
3.4 读取数据
读取数据也是通过事务完成。
function read() {
var transaction = db.transaction(['person']);
var objectStore = transaction.objectStore('person');
var request = objectStore.get(1); request.onerror = function(event) {
console.log('事务失败');
}; request.onsuccess = function( event) {
if (request.result) {
console.log('Name: ' + request.result.name);
console.log('Age: ' + request.result.age);
console.log('Email: ' + request.result.email);
} else {
console.log('未获得数据记录');
}
};
} read();
上面代码中,objectStore.get()
方法用于读取数据,参数是主键的值。
3.5 遍历数据
遍历数据表格的所有记录,要使用指针对象 IDBCursor。
function readAll() {
var objectStore = db.transaction('person').objectStore('person'); objectStore.openCursor().onsuccess = function (event) {
var cursor = event.target.result; if (cursor) {
console.log('Id: ' + cursor.key);
console.log('Name: ' + cursor.value.name);
console.log('Age: ' + cursor.value.age);
console.log('Email: ' + cursor.value.email);
cursor.continue();
} else {
console.log('没有更多数据了!');
}
};
} readAll();
上面代码中,新建指针对象的openCursor()
方法是一个异步操作,所以要监听success
事件。
3.6 更新数据
更新数据要使用IDBObject.put()
方法。
function update() {
var request = db.transaction(['person'], 'readwrite')
.objectStore('person')
.put({ id: 1, name: '李四', age: 35, email: 'lisi@example.com' }); request.onsuccess = function (event) {
console.log('数据更新成功');
}; request.onerror = function (event) {
console.log('数据更新失败');
}
} update();
上面代码中,put()
方法自动更新了主键为1
的记录。
3.7 删除数据
IDBObjectStore.delete()
方法用于删除记录。
function remove() {
var request = db.transaction(['person'], 'readwrite')
.objectStore('person')
.delete(1); request.onsuccess = function (event) {
console.log('数据删除成功');
};
} remove();
3.8 使用索引
索引的意义在于,可以让你搜索任意字段,也就是说从任意字段拿到数据记录。如果不建立索引,默认只能搜索主键(即从主键取值)。
假定新建表格的时候,对name
字段建立了索引。
objectStore.createIndex('name', 'name', { unique: false });
现在,就可以从name
找到对应的数据记录了。
var transaction = db.transaction(['person'], 'readonly');
var store = transaction.objectStore('person');
var index = store.index('name');
var request = index.get('李四'); request.onsuccess = function (e) {
var result = e.target.result;
if (result) {
// ...
} else {
// ...
}
}
浏览器数据库 IndexedDB 入门教程的更多相关文章
- 浏览器数据库 IndexedDB 入门
一.概述 随着浏览器的功能不断增强,越来越多的网站开始考虑,将大量数据储存在客户端,这样可以减少从服务器获取数据,直接从本地获取数据. 现有的浏览器数据储存方案,都不适合储存大量数据:Cookie 的 ...
- 浏览器数据库IndexedDB介绍
摘要 在移动端H5页面开发的时候,为了更好的提高用户体验,可以对不常变化的数据做浏览器端数据缓存,在用户打开页面的时候,首先加载本地的数据,然后异步请求服务端,更新数据.在移动端webview中,可以 ...
- Oracle数据库初学者入门教程
Oracle数据库是相对于其他数据库来说比较难的一个.Oracle Database,又名Oracle RDBMS,简称Oracle.是甲骨文公司推出的一款关系数据库管理系统.Oracle数据库系统是 ...
- ABP入门教程0 - 目录
ABP入门教程 本教程主要讲解如何基于ABP实现CURD(增删改查)示例. 源码已分享: GitHub Gitee ABP入门教程0 - 目录 ABP入门教程1 - 开篇 ABP入门教程2 - ...
- HR问了一句DB是啥?SQL是啥?DB是Database数据库,SQL是数据库语言! 然后呢? 数据库从入门到精通--入门必看!
写在前面 本文的写作知识体系来源于我的数据库老师SDAU张承明,部分知识来自于网络,我呢对知识进行了细化和添加了自己的一些看法,并且加入了一些实例帮助理解,本文不是面向SQL高手写的,可以看作是数据库 ...
- 超强、超详细Redis数据库入门教程
这篇文章主要介绍了超强.超详细Redis入门教程,本文详细介绍了Redis数据库各个方面的知识,需要的朋友可以参考下 [本教程目录] 1.redis是什么2.redis的作者何许人也3.谁在使用red ...
- SQLite数据库入门教程
SQLite数据库入门教程 SQLite 是一个开源的嵌入式关系数据库,实现自包容.零配置.支持事务的SQL数据库引擎. 其特点是高度便携.使用方便.结构紧凑.高效.可靠. 与其他数据库管理系统不同, ...
- 超强、超详细Redis数据库入门教程(转载)
这篇文章主要介绍了超强.超详细Redis入门教程,本文详细介绍了Redis数据库各个方面的知识,需要的朋友可以参考下 [本教程目录] 1.redis是什么 2.redis的作者何许人也 3.谁在使 ...
- Spring Boot入门教程2-1、使用Spring Boot+MyBatis访问数据库(CURD)注解版
一.前言 什么是MyBatis?MyBatis是目前Java平台最为流行的ORM框架https://baike.baidu.com/item/MyBatis/2824918 本篇开发环境1.操作系统: ...
随机推荐
- java中的数据加密1 消息摘要
消息摘要(Message Digest) 又称为数字摘要(Digital Digest).它是一个唯一对应一个消息或文本的固定长度的值,它由一个单向Hash加密函数对消息进行作用而产生.如果消息在途中 ...
- RTMP之后,SRT与QUIC
RTMP协议存在累计延迟与加密方面的问题,为适应互联网视频低延时,高质量的要求,以UDP为核心,具有创造性的SRT,QUIC等流媒体视频方式将成为新的选择 RTMP协议最初是由Macromedia为通 ...
- python 简单的server请求
1.代码 #!/usr/bin/env python3 # -*- coding: utf-8 -*- # __author henry # __date 2018/11/4 from wsgiref ...
- Pika的设计及实现
Pika pika是360奇虎公司开源的一款类redis存储系统,主要解决的是用户使用 Redis 的内存大小超过 50G.80G 等等这样的情况,会遇到启动恢复时间长,一主多从代价大,硬件成本贵,缓 ...
- QT 窗口拖拽移动实现
我们知道,要实现窗口移动可以直接鼠标点住窗口的标题栏实现拖拽移动,这是窗口默认的行为,在QT中的事件响应函数为moveEvent. 但是现实中经常需要鼠标点住窗口客户区域实现窗口的拖拽移动,代码实现如 ...
- Pyhthon爬虫其之验证码识别
背景 现在的登录系统几乎都是带验证手段的,至于验证的手段也是五花八门,当然用的最多的还是验证码.不过纯粹验证码识已经是很落后的东西了,现在比较多见的是滑动验证,滑动拼图验证(这个还能往里面加广告).点 ...
- [Linux] 如何禁止使用口令只允许使用密钥建立 SSH 连接
1. 创建 SSH KEY 使用 ssh-keygen 生成一个密钥对,并且将公钥注册到服务器的 $HOME/.ssh/authorized_keys 文件. 2. 确保启用 SSH 公钥认证功能 查 ...
- [Linux] ssh-key 公钥文件格式
SSH 协议(Secure Shell 协议)最初在 1995 年由芬兰的 Tatu Ylönen 设计开发,由 IETF(Internet Engineering Task Force)的网络工作小 ...
- 利用media query让背景图适应不同分辨率的设备
随着上网方式的多样化,用户选择上网的工具不再仅是PC,而可以是手机,或者平板电脑.随之而来的问题是如何让网页适应不同分辨率,这给前端工程师们带来了新的挑战,其中重要的一点是如何让图片能在不同的分辨率下 ...
- 【zheng阅读系列】shiro权限管理
一.配置文件 upms-server/springMVC-servlet.xml <?xml version="1.0" encoding="UTF-8" ...