IndexedDB浏览器本地存储缓存数据库CookieLocal StorageSession StorageWeb SQL
Posted web半晨
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IndexedDB浏览器本地存储缓存数据库CookieLocal StorageSession StorageWeb SQL相关的知识,希望对你有一定的参考价值。
目录
1、前言
在人们的印象中,可能觉得只有做后端的小伙伴才会接触到数据库。其实在前端的领域里面也有数据库,只是可能用的比较少,因为前端存储方案有很多,比如
Cookie
、Session Storage
等等。
在浏览器上有两种数据库:Web SQL
和IndexedDB
。但是如果在浏览器上需要用到数据库一般会使用IndexedDB
数据库,Web SQL
基本上已经废弃了,具体原因小伙伴可以下来自己查查,今天主要就讲解IndexedDB
数据库的使用。
2、IndexedDB简介
MDN官网是这样解释IndexedDB的
IndexedDB
是一种底层API,用于在客户端存储大量的结构化数据,也包括文件/二进制大型对象(blobs)。该API使用索引实现对数据的高性能搜索。虽然Web Storage
在存储较少量的数据很有用,但对于存储更大量的结构化数据来说力不从心。而IndexedDB
提供了这种场景的解决方案。
官网上的这句话也很简单明了,意思就是IndexedDB
主要用来客户端存储大量数据而生的,我们都知道cookie
、localstorage
等存储方式都有存储大小限制。如果数据量很大,且都需要客户端存储时,那么就可以使用IndexedDB
数据库。
客户端各存储方式对比
会话期 Cookie | 持久性 Cookie | SessionStorage | LocalStorage | IndexeDB | Web SQL | |
---|---|---|---|---|---|---|
存储大小 | 4KB | 4KB | 2.5MB~10MB | 2.5MB~10MB | >250MB | 已废弃 |
失效时间 | 浏览器关闭自动清除 | 设置过期时间,到期后清除 | 浏览器关闭后清除 | 永久保存,除非手动清除 | 手动更新或删除 | 已废弃 |
与服务端交互 | 有 | 有 | 无 | 无 | 无 | 已废弃 |
访问策略 | 符合同源策略,可以访问 | 符合同源策略,可以访问 | 符合同源策略,可以访问 | 即使同源也不可相互访问 | 符合同源策略,可以访问 | 已废弃 |
3、IndexedDB使用场景
所有的场景都基于客户端需要存储大量数据的前提下。
1、数据可视化等界面,大量数据,每次请求会消耗很大性能。
2、即时聊天工具,大量消息需要存在本地。
3、其它存储方式容量不满足时,不得已使用IndexedDB
4、IndexedDB特点
4.1、非关系型数据库 NoSql
我们都知道
mysql
等数据库都是关系型数据库,它们的主要特点就是数据都以一张二维表的形式存储,而IndexedDB
是非关系型数据库,主要以键值对的形式存储数据。
4.2、持久化存储
Cookie
、Local Storage
、Session Storage
等方式存储的数据当我们清楚浏览器缓存后,这些数据都会被清除掉的,而使用IndexedDB
存储的数据则不会,除非手动删除该数据库。
4.3、异步操作
IndexedDB
操作时不会锁死浏览器,用户依然可以进行其他的操作,这与Local Storage
形成鲜明的对比,后者是同步。
4.4、支持事务
IndexedDB
支持事务transaction
,这意味着一系列的操作步骤之中,只要有一步失败了,整个事务都会取消,数据库回滚的事务发生之前的状态,这和MySQL
等数据库的事务类似。
4.5、同源策略
IndexedDB
同样存在同源限制,每个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。
4.6、存储容量大
这也是
IndexedDB
最显著的特点之一了,这也是不用Local Storage
等存储方式的最好理由。
5、IndexedDB重要概念讲解
5.1、仓库objectStore
IndexedDB
没有表的概念,它只有仓库store
的概念,大家可以把仓库理解为表即可,即一个store
是一张表。
5.2、索引index
在关系型数据库当中也有索引的概念,我们可以给对应的表字段添加索引,以便加快查找速率。在
IndexedDB
中同样有索引,我们可以在创建store
的时候同时创建索引,在后续对store
进行查询的时候即可通过索引来筛选,给某个字段添加索引后,在后续插入数据的过成功,索引字段便不能为空。
5.3、游标cursor
游标是
IndexedDB
数据库新的概念,大家可以把游标想象为一个指针,比如我们要查询满足某一条件的所有数据时,就需要用到游标,我们让游标一行一行的往下走,游标走到的地方便会返回这一行数据,此时我们便可对此行数据进行判断,是否满足条件。
【注意】:IndexedDB
查询不像MySQL
等数据库方便,它只能通过主键、索引、游标方式查询数据。
5.4、事务
IndexedDB
支持事务,即对数据库进行操作时,只要失败了,都会回滚到最初始的状态,确保数据的一致性。
6、IndexedDB实操
IndexedDB
所有针对仓库的操作都基于事务。
6.1、创建或连接数据库
/*
* 打开数据库
* @param object dbName 数据库的名字
* @param string storeName 仓库名称
* @param string version 数据库的版本
* @return object 该函数会返回一个数据库实例
*/
function openDB(dbName, version = 1)
return new Promise((resolve, reject) =>
// 兼容浏览器
var indexedDB =
window.indexedDB ||
window.mozIndexedDB ||
window.webkitIndexedDB ||
window.msIndexedDB;
let db;
// 打开数据库,若没有则会创建
const request = indexedDB.open(dbName, version);
// 数据库打开成功回调
request.onsuccess = function (event)
// 数据库对象
db = event.target.result;
console.log("数据库打开成功");
resolve(db);
;
// 数据库打开失败的回调
request.onerror = function (event)
console.log("数据库打开报错");
;
// 数据库有更新时候的回调
request.onupgradeneeded = function (event)
// 数据库创建或升级的时候会触发
console.log("onupgradeneeded");
// 数据库对象
db = event.target.result;
var objectStore;
// 创建存储库
objectStore = db.createObjectStore("signalChat",
// 这是主键
keyPath: "sequenceId",
// 实现自增
// autoIncrement: true
);
// 创建索引,在后面查询数据的时候可以根据索引查
objectStore.createIndex("link", "link", unique: false );
objectStore.createIndex("sequenceId", "sequenceId", unique: false );
objectStore.createIndex("messageType", "messageType",
unique: false,
);
;
);
我们将创建数据库的操作封装成了一个函数,并且该函数返回一个
Promise
对象,使得在调用的时候可以链式调用,函数主要接收两个参数,数据库名称、数据库版本。函数内部主要有三个回调函数。
onsuccess
:数据库打开成功或者创建成功后的回调,这里我们将数据库实例返回了出去。
onerror
:数据库打开或创建失败后的回调。
onupgradeneeded
:当数据库版本有变化的时候会执行该函数,比如我们想创建新的存储库(表),就可以在该函数里面操作,更新数据库版本即可。
6.2、插入数据
/*
* 新增数据
* @param object db 数据库实例
* @param string storeName 仓库名称
* @param string data 数据
*/
function addData(db, storeName, data)
var request = db
// 事务对象 指定表格名称和操作模式("只读"或"读写")
.transaction([storeName], "readwrite")
// 仓库对象
.objectStore(storeName)
.add(data);
request.onsuccess = function (event)
console.log("数据写入成功");
;
request.onerror = function (event)
console.log("数据写入失败");
;
IndexedDB
插入数据需要通过事务来进行操作,插入的方法也很简单,利用IndexedDB
提供的add方法即可,这里我们同样将插入数据的操作封装成了一个函数,接收三个参数。
db
:在创建或连接数据库时,返回的db实例,需要那个时候保存下来。
storeName
:仓库名称(或者表名),在创建或连接数据库时我们就已经创建好了仓库。
data
:需要插入的数据,通常是一个对象。
【注意】:插入的数据是一个对象,而且必须包含我们声明的索引键值对。
6.3、通过主键读取数据
/*
* 通过主键读取数据
* @param object db 数据库实例
* @param string storeName 仓库名称
* @param string key 主键值
*/
function getDataByKey(db, storeName, key)
return new Promise((resolve, reject) =>
// 事务
var transaction = db.transaction([storeName]);
// 仓库对象
var objectStore = transaction.objectStore(storeName);
// 通过主键获取数据
var request = objectStore.get(key);
request.onerror = function (event)
console.log("事务失败");
;
request.onsuccess = function (event)
console.log("主键查询结果: ", request.result);
resolve(request.result);
;
);
主键即刚刚我们在创建数据库时声明的
keyPath
,通过主键只能查询出一条数据。
6.4、通过游标查询数据
/*
* 通过游标读取数据
* @param object db 数据库实例
* @param string storeName 仓库名称
*/
function cursorGetData(db, storeName)
let list = [];
var store = db
// 事务
.transaction(storeName, "readwrite")
// 仓库对象
.objectStore(storeName);
// 指针对象
var request = store.openCursor();
// 游标开启成功,逐行读数据
request.onsuccess = function (e)
var cursor = e.target.result;
if (cursor)
// 必须要检查
list.push(cursor.value);
// 遍历了存储对象中的所有内容
cursor.continue();
else
console.log("游标读取的数据:", list);
;
上面函数开启了一个游标,然后逐行读取数据,存入数组,最终得到整个仓库的所有数据。
6.5、通过索引查询数据
/*
* 通过索引读取数据
* @param object db 数据库实例
* @param string storeName 仓库名称
* @param string indexName 索引名称
* @param string indexValue 索引值
*/
function getDataByIndex(db, storeName, indexName, indexValue)
var store = db.transaction(storeName, "readwrite").objectStore(storeName);
var request = store.index(indexName).get(indexValue);
request.onerror = function ()
console.log("事务失败");
;
request.onsuccess = function (e)
var result = e.target.result;
console.log("索引查询结果:", result);
;
索引名称即我们创建仓库的时候创建的索引名称,也就是键值对中的键,最终会查询出所有满足我们传入函数索引值的数据。
6.6、通过索引和游标查询数据
通过6.4节和6.5节我们发现,单独通过索引或者游标查询出的数据都是部分或者所有数据,如果我们想要查询出索引中满足某些条件的所有数据,那么单独使用索引或游标是无法实现的。当然,你也可以查询出所有数据之后在循环数组筛选出合适的数据,但是这不是最好的实现方式,最好的方式当然是将索引和游标结合起来。
/*
* 通过索引和游标查询记录
* @param object db 数据库实例
* @param string storeName 仓库名称
* @param string indexName 索引名称
* @param string indexValue 索引值
*/
function cursorGetDataByIndex(db, storeName, indexName, indexValue)
let list = [];
// 仓库对象
var store = db.transaction(storeName, "readwrite").objectStore(storeName);
var request = store
// 索引对象
.index(indexName)
// 指针对象
.openCursor(IDBKeyRange.only(indexValue));
request.onsuccess = function (e)
var cursor = e.target.result;
if (cursor)
// 必须要检查
list.push(cursor.value);
// 遍历了存储对象中的所有内容
cursor.continue();
else
console.log("游标索引查询结果:", list);
;
request.onerror = function (e) ;
上面函数接收四个参数
db
:数据库实例
storeName
:仓库名
indexName
:索引名称
indexName
:索引值
利用索引和游标结合查询,我们可以查询出索引值满足我们传入函数值的所有数据对象,而不是之查询出一条数据或者所有数据。
6.7、通过索引和游标分页查询
IndexedDB
分页查询不像MySQL
分页查询那么简单,没有提供现成的API
,如limit
等,所以需要我们自己实现分页。
/*
* 通过索引和游标分页查询记录
* @param object db 数据库实例
* @param string storeName 仓库名称
* @param string indexName 索引名称
* @param string indexValue 索引值
* @param number page 页码
* @param number pageSize 查询条数
*/
function cursorGetDataByIndexAndPage(
db,
storeName,
indexName,
indexValue,
page,
pageSize
)
let list = [];
// 计数器
let counter = 0;
// 是否跳过多少条查询
let advanced = true;
// 仓库对象
var store = db.transaction(storeName, "readwrite").objectStore(storeName);
var request = store
// 索引对象
.index(indexName)
// 指针对象
.openCursor(IDBKeyRange.only(indexValue));
request.onsuccess = function (e)
var cursor = e.target.result;
if (page > 1 && advanced)
advanced = false;
// 跳过多少条
cursor.advance((page - 1) * pageSize);
return;
if (cursor)
// 必须要检查
list.push(cursor.value);
counter++;
if (counter < pageSize)
// 遍历了存储对象中的所有内容
cursor.continue();
else
cursor = null;
console.log("分页查询结果", list);
else
console.log("分页查询结果", list);
;
request.onerror = function (e) ;
这里用到了
IndexedDB
的一个API
:advance
。该函数可以让我们的游标跳过多少条开始查询。假如我们的额分页是每页10
条数据,现在需要查询第2
页,那么我们就需要跳过前面10
条数据,从11
条数据开始查询,直到计数器等于10
,那么我们就关闭游标,结束查询。
6.8、更新数据
IndexedDB
更新数据较为简单,直接使用put
方法,值得注意的是如果数据库中没有该条数据,则会默认增加该条数据,否则更新。有些小伙伴喜欢更新和新增都是用put
方法,这也是可行的。
/*
* 更新数据
* @param object db 数据库实例
* @param string storeName 仓库名称
* @param object data 数据
*/
function updateDB(db, storeName, data)
var request = db
// 事务对象
.transaction([storeName], "readwrite")
// 仓库对象
.objectStore(storeName)
.put(data);
request.onsuccess = function ()
console.log("数据更新成功");
;
request.onerror = function ()
console.log("数据更新失败");
;
put
方法接收一个数据对象。
6.9、通过主键删除数据
主键即我们创建数据库时申明的
keyPath
,它是唯一的。
/*
* 通过主键删除数据
* @param object db 数据库实例
* @param string storeName 仓库名称
* @param object id 主键值
*/
function deleteDB(db, storeName, id)
var request = db
.transaction([storeName], "readwrite")
.objectStore(storeName)
.delete(id);
request.onsuccess = function ()
console.log("数据删除成功");
;
request.onerror = function ()
console.log("数据删除失败");
;
该种删除只能删除一条数据,必须传入主键。
6.10、通过索引和游标删除指定数据
有时候我们拿不到主键值,只能只能通过索引值来删除,通过这种方式,我们可以删除一条数据(索引值唯一)或者所有满足条件的数据(索引值不唯一)。
/*
* 通过索引和游标删除指定的数据
* @param object db 数据库实例
* @param string storeName 仓库名称
* @param string indexName 索引名
* @param object indexValue 索引值
*/
function cursorDelete(db, storeName, indexName, indexValue)
var store = db.transaction(storeName, "readwrite").objectStore(storeName);
var request = store
// 索引对象
.index(indexName)
// 指针对象
.openCursor(IDBKeyRange.only(indexValue));
request.onsuccess = function (e)
var cursor = e.target.result;
var deleteRequest;
if (cursor)
// 请求删除当前项
deleteRequest = cursor.delete();
deleteRequest.onerror = function ()
console.log("游标删除该记录失败");
;
deleteRequest.onsuccess = function ()
console.log("游标删除该记录成功");
;
cursor.continue();
;
request.onerror = function (e) ;
上段代码可以删除索引值为
indexValue
的所有数据,值得注意的是使用了IDBKeyRange.only()API,该API代表只能当两个值相等时,具体API解释可参考MDN官网。
6.11、关闭数据库
当我们数据库操作完毕后,建议关闭它,节约资源。
/*
* 关闭数据库
* @param object db 数据库实例
*/
function closeDB(db)
db.close();
console.log("数据库已关闭");
6.12、删除数据库
最后我们需要删库跑路,删除操作也很简单。
/*
* 删除数据库
* @param object dbName 数据库名称
*/
function deleteDBAll(dbName)
console.log(dbName);
let deleteRequest = window.indexedDB.deleteDatabase(dbName);
deleteRequest.onerror = function (event以上是关于IndexedDB浏览器本地存储缓存数据库CookieLocal StorageSession StorageWeb SQL的主要内容,如果未能解决你的问题,请参考以下文章
懂你网络系列7之浏览器缓存cookie,sessions,localStorage,sessioStoage,indexedDB
懂你网络系列7之浏览器缓存cookie,sessions,localStorage,sessioStoage,indexedDB