前端本地数据库 indexedDB 实践

569 阅读3分钟

「这是我参与2022首次更文挑战的第22天,活动详情查看:2022首次更文挑战

前言

说到数据库,可能大家印象当中都会认为是后端的数据库,其实前端也有数据库,只不过前端需要存储的数据量不会有那么多,正常情况下 cookie、localStorage 等等方案已经足够用了,所以前端本地数据库用的会比较少,今天我们就学习一下 indexedDB 的使用

介绍

IndexedDB 是一种底层 API,是一个事务型数据库系统,用于在客户端存储大量的结构化数据(也包括文件/二进制大型对象(blobs))。该 API 使用索引实现对数据的高性能搜索。对于存储更大量的结构化数据来说使用 IndexedDB 是一个很好的解决方案。

下面我们与 Cookie、sessionStorage、localStorage 进行一个对比

标题CookiesessionStoragelocalStorageindexedDB
存储大小4kb2.5MB - 10MB2.5MB - 10MB>250MB
失效时间设置过期时间,到期后清除 或者 关闭浏览器清除关闭浏览器清除永久保存手动更新
与服务端交互
访问策略同源策略同源策略同源也不可互相访问同源策略

由上面这张表可以知道,indexedDB 适合大数据量的场景。而且使用 indexedDB 执行的操作是异步执行的,以免阻塞应用程序。

使用

创建或连接数据库

// 打开数据库
const request = window.indexedDB.open("MyTestDatabase");
var db;
// 数据库打开成功回调
request.onsuccess = function (event) {
  db = event.target.result; // 数据库对象
  console.log("数据库打开成功");
};
// 数据库打开失败的回调
request.onerror = function (event) {
  console.log("数据库打开报错");
};
// 数据库有更新时候的回调
request.onupgradeneeded = function (event) {
  // 数据库创建或升级的时候会触发
  console.log("onupgradeneeded");
  db = event.target.result; // 数据库对象
  
  // 建立一个对象仓库来存储我们客户的相关信息,我们选择 ssn 作为键路径(key path)
  // 因为 ssn 可以保证是不重复的
  var objectStore = db.createObjectStore("customers", { keyPath: "ssn" });

  // 建立一个索引来通过姓名来搜索客户。名字可能会重复,所以我们不能使用 unique 索引
  objectStore.createIndex("name", "name", { unique: false });

  // 使用邮箱建立索引,我们向确保客户的邮箱不会重复,所以我们使用 unique 索引
  objectStore.createIndex("email", "email", { unique: true });
}

open 请求不会立即打开数据库或者开始一个事务,他是一个异步操作,所以我们需要监听 request.onsuccess 事件,来判断是否打开成功。 indexedDB.open 方法的第二个参数可以传入版本号,版本号不能是浮点数。

增加数据

首先需要通过transaction方法返回一个事务对象,指定表格名称和操作模式("只读"或"读写"),还有仓库对象。

var transaction = db.transaction(["customers"], "readwrite"); // 表
var objectStore = transaction.objectStore("customers"); // 仓库对象
objectStore.add({ ssn: '1', name: '张三', age: 35, email: '张三@company.com' })

这时候就添加了一条数据,我们可以打开开发者工具的 Application - IndexedDB 查看数据库

image.png

因为我们创建了两个索引,所以表customers里有name和email

通过主键读取数据

因为刚刚我们设置了 ssn 字段为我们的主键,所以通过 objectStore.get方法,获取到 ssn === 1 的数据

var transaction = db.transaction(['customers'], 'readwrite'); // 事物对象
var objectStore = transaction.objectStore('customers'); // 仓库对象
const request = objectStore.get('1');
request.onerror = function(event) {
    // 错误处理!
};
request.onsuccess = function(event) {
    console.log(request.result);
};

更新数据

上一步我们获取到数据以后可以继续进行更新数据

var transaction = db.transaction(['customers'], 'readwrite'); // 事物对象
var objectStore = transaction.objectStore('customers'); // 仓库对象
const request = objectStore.get('1');
request.onerror = function(event) {
    // 错误处理!
};
request.onsuccess = function(event) {
    var data = event.target.result;

    // 更新你想修改的数据
    data.age = 42;
    // 把更新过的对象放回数据库
    var requestUpdate = objectStore.put(data);
    requestUpdate.onerror = function(event) {
     // 错误处理
    };
    requestUpdate.onsuccess = function(event) {
     // 完成,数据已更新!
    };
};

通过put 方法进行修改

删除数据

删除数据的操作很简单,

var request = db.transaction(["customers"], "readwrite")
                .objectStore("customers")
                .delete("444-44-4444");
request.onsuccess = function(event) {
  // 删除成功!
};

总结

indexedDB 在一些数据量大的场景中使用 indexedDB 会更加高效。
兼容性

image.png