目次
序文:
ブラウザーには、webSQL と IndexedDB という 2 つのデータベースがあります。ただし、ブラウザ上でデータベースを使用する必要がある場合は、一般的に Indexed DB データベースを使用することになり、webSQL は基本的に放棄されました。
WebSQL は SQL ベースのブラウザー ローカル ストレージ テクノロジであり、HTML5 では標準化されていないテクノロジです。WebSQL はシナリオによっては使用すると便利ですが、W3C によって標準化されていないため、いくつかの問題が発生します。
- ブラウザ間の互換性の問題。WebSQL のサポートのレベルはブラウザによって異なり、ブラウザによっては WebSQL をまったくサポートしていないため、モバイル端末上の WebSQL と PC 端末間の互換性の問題が発生します。
- セキュリティ上の問題。WebSQL には潜在的なセキュリティ リスクがいくつかあり、たとえば、攻撃者が悪意のある SQL ステートメントを挿入してユーザー データを取得する可能性があります。
- データベースのサイズ制限。WebSQL のデータベース容量制限はブラウザごとに実装されており、普遍的な標準はなく、ほとんどのブラウザにはデータベース サイズの制限があります。
したがって、W3C はWebSQL の代替としてIndexedDB 標準を立ち上げ、主要なブラウザでサポートされています。IndexedDB は、クロスプラットフォーム互換性が向上し、安全性と信頼性が高く、トランザクションと非同期操作をサポートし、最新のモバイル アプリケーションやオンライン データ ストレージ アプリケーションのニーズをより適切に満たすことができます。
(Cookie、セッションストレージなどのフロントエンドストレージソリューション)
1.IndexedDB の概要
MDN 公式 Web サイトでは、Indexed DB について次のように説明されています。
IndexedDBは、クライアント側に大量の構造化データ (ファイル/バイナリ ラージ オブジェクト (BLOB) も) を保存するための低レベル API です。API はインデックスを使用して、データの高性能検索を可能にします。Web Storage は少量のデータを保存するには便利ですが、大量の構造化データを保存するには不十分です。IndexedDB は、このシナリオに対するソリューションを提供します。
Cookie や localStorage などのストレージ メソッドにはストレージ サイズの制限があるため、データ量が多くクライアント ストレージが必要な場合は、IndexedDB データベースを使用してください。
セッションクッキー | 永続的な Cookie | セッション ストレージ |
ローカル ストレージ |
インデックス付きDB | WebsQL | |
収納サイズ | 4kb | 4kb | 2.5~10MB | 2.5~10MB | >250MB | 廃止されました |
有効期限 | ブラウザが閉じて自動的にクリアされる | 有効期限を設定し、 有効期限が切れたらクリアする |
ブラウザを閉じ たらクリア |
永久に保存します ( 手動でクリアしない限り) |
手動更新 または削除 |
廃止されました |
サーバーと対話する | 持っている | 持っている | なし | なし | なし | 廃止されました |
アクセスポリシー | 同一オリジンポリシーに従ってアクセス可能 | 同一オリジンポリシーに準拠して アクセス可能 |
同一オリジンポリシーに準拠してアクセス 可能 |
たとえオリジンが同じであっても 、 相互にアクセスすることはできません。 |
同一生成元 ポリシーに準拠すると、アクセサーが 非推奨になる可能性があります |
廃止されました |
2.IndexedDBの利用シナリオ
すべてのシナリオは、クライアントが大量のデータを保存する必要があるという前提に基づいています。
- データ視覚化、大量のデータ、各リクエストなどのインターフェイスは、多くのパフォーマンスを消費します。
- インスタント チャット ツールの場合、大量のメッセージをローカルに保存する必要があります。
- 他のストレージ方法では容量が不十分な場合は、最後の手段として IndexedDB を使用する必要があります。
3.IndexedDBの機能
(1) 非リレーショナルデータベース(NoSql)
MySQL などのデータベースはリレーショナル データベースであり、データが2 次元のインデックス DB は主にキーと値のペアの形式でデータを格納する非リレーショナル データベースです。
(2) 永続ストレージ
Cookie、localStorage、sessionStorage などに保存されたデータはブラウザのキャッシュをクリアするとクリアされますが、IndexedDB を使用して保存されたデータはデータベースが手動で削除されない限りクリアされません。
(3)非同期動作
IndexedDB は操作中にブラウザをロックせず (非同期)、ユーザーは他の操作を実行できますが、これは
同期である localstorage とは大きく異なります。
(4)支援事務
IndexedDB はトランザクションをサポートしています。つまり、一連の操作ステップの 1 つのステップが失敗すると、トランザクション全体がキャンセルされ、データベースはトランザクションが発生する前の状態にロールバックされます。これは、MySQL などのデータベースのトランザクションと同様です。
(5) 同一起源戦略
IndexedDB には同一オリジン制限もあり、各データベースはそれが作成されたドメイン名に対応します。Web ページは、独自のドメイン名のデータベースにのみアクセスできますが、クロスドメイン データベースにはアクセスできません。
(6) 大容量のストレージ
IndexedDB の最も重要な機能の 1 つは、localStorage などのストレージ メソッドを使用しない最大の理由でもあります。
4.IndexedDBの概念補足
①倉庫オブジェクトストア
IndexedDBには、テーブルとして理解できるウェアハウス ストアの概念のみがあり、ストアにはテーブルの概念はなく、単なるテーブルです。
②インデックスインデックス
リレーショナルデータベースにはインデックスという概念があり、対応するテーブルフィールドにインデックスを追加することで検索速度を高速化することができます。IndexedDB にはインデックスもあります。インデックスはストアの作成時に同時に作成できます。その後ストアにクエリを実行するときに、インデックスでフィルタリングできます。フィールドにインデックスを追加した後、その後のデータ挿入が成功すると、インデックスフィールド 空にすることはできません。
③カーソル
カーソルは IndexedDB データベースの新しい概念です。カーソルをポインタと考えることができます。特定の条件を満たすすべてのデータをクエリする場合は、カーソルを使用する必要があります。カーソルを 1 行ずつ下に移動させます。この行のデータを返すと、この行のデータが条件を満たしているかどうかを判断できます。
⭕注: IndexedDB クエリは MySQL などのデータベースほど便利ではなく、主キー、インデックス、カーソルを介してのみデータをクエリできます。
④事務
IndexedDB はトランザクション、つまりデータベース操作時に障害が発生する限りの一貫性をサポートします。データが確実に元の状態にロールバックされます。
5.IndexedDBの実際の操作
IndexedDB のウェアハウスでのすべての操作はトランザクション ベースです。
①データベースを作成または接続する
//打开数据库
//@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 = fuction(evetn){
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 オブジェクトを返すため、呼び出されたときにチェーンで呼び出すことができます。関数は主にデータベース名とデータベース バージョンの 2 つのパラメータを受け取ります。関数内には、次の 3 つの主要なコールバック関数があります。
- onsuccess: データベースが正常にオープンまたは作成された後のコールバック。ここではデータベース インスタンスを返します。
- onerror: データベースのオープンまたは作成が失敗した後のコールバック。
- onupgradeneeded: データベースのバージョンが変更されたときにこの関数が実行されます。たとえば、新しいリポジトリ (テーブル) を作成する場合、この関数を操作してデータベースのバージョンを更新できます。
②データの挿入
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 メソッドを使用するだけです。ここでは、データの挿入操作も、次のように 3 つのパラメータを受け取る関数にカプセル化されています。
- db: データベースを作成または接続するとき、返された db インスタンスをその時点で保存する必要があります。
- storeName: ウェアハウス名 (またはテーブル名)。ウェアハウスは、データベースの作成時またはデータベースへの接続時に作成されています。
- data: 挿入されるデータ、通常はオブジェクト
⭕注: 挿入されたデータはオブジェクトであり、宣言されたインデックスのキーと値のペアが含まれている必要があります。
③主キー経由でデータを読み取る
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);
};
});
}
④ カーソルによるデータのクエリ
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);
}
};
}
⑤ インデックスによるデータのクエリ
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);
};
}
インデックス名は、ウェアハウスの作成時に作成されたインデックス名であり、キーと値のペアのキーです。受信関数のインデックス値を満たすすべてのデータが最終的にクエリされます。
インデックス名は、ウェアハウスの作成時に作成されたインデックス名であり、キーと値のペアのキーです。最終的には、関数に渡されたインデックス値を持つ 1 つのデータのみがクエリされます。
⑥ インデックスとカーソルによるデータのクエリ
インデックスまたはカーソルのみを使用してクエリされるデータは、データの一部またはすべてです。特定の条件を満たすインデックス内のすべてのデータをクエリする場合、インデックスまたはカーソルを単独で使用することはできません。もちろん、すべてのデータをクエリして、ループ配列内の適切なデータをフィルターで除外することもできますが、これは最良の実装方法ではなく、インデックスとカーソルを組み合わせることです。
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) {};
}
⑦インデックスとカーソルによるクエリのページング
IndexedDB のページング クエリは MySQL のページング クエリほど単純ではなく、limit などの既製の API が提供されていないため、ページングを自分で実装する必要があります。
function cursorGetDataByIndexAndPage(
db , //数据库实例
storeName,
indexName,
indexValue,
page,
pageSize
){
let list = []; //设置空数组用来保存实例
let counter = ; // 计数器——停止游标
let advanced = true; // 是否跳过多少条查询
var store = db.transaction(storeName, "readwrite"),obiectStore(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:advanced。この関数を使用すると、カーソルはクエリを開始する項目の数をスキップできます。ページングが 1 ページあたり 10 個のデータであり、2 番目のページをクエリする必要がある場合、最初の 10 個のデータをスキップし、11 番目のデータからクエリを開始し、カウンタが 10 に等しくなるまでクエリを開始し、その後閉じる必要があります。カーソルを移動してクエリを終了します。
⑧データ更新
IndexedDB のデータを更新するのは比較的簡単です。put メソッドを直接使用します。データがデータベースに存在しない場合はデフォルトでデータが追加され、存在しない場合は更新されることに注意してください。更新や新規追加に put メソッドを使用したい場合は、これも可能です。
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 メソッドはデータ オブジェクトを受け取ります
⑨主キーによるデータ削除
主キーはデータベースの作成時に宣言された keyPath であり、一意です。
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("数据删除失败");
};
}
⑩インデックスとカーソルで指定したデータを削除
主キーの値が取得できず、インデックス値によってのみ削除できる場合があります。このようにして、データの一部 (インデックス値が一意である) または条件を満たすすべてのデータ (インデックス値が一意ではない) を削除できます。 )。
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.only0APIが使用されていることは注目に値します.このAPIは、2つの値が等しい場合にのみ使用できることを意味します. 具体的なAPIの説明については、を参照してくださいMDN公式サイトへ。
⑪データベースを閉じる
データベース操作が完了したら、リソースを節約するためにデータベースを閉じることをお勧めします。
function closeDB(db) {
db.close();
console.log("数据库已关闭");
}
⑫データベースの削除
function deleteDBAll(dbName){
console.log(dbName);
let deleteRequest = window,indexedDB.deleteDatabase(dbName);
deleteRequest.onerror = function (event) {
console.log("删除失败");
};
deleteRequest.onsuccess = function (event) {
console.log("删除成功");
};
}
要約:
IndexedDB は、ブラウザ側で大量の構造化データを保存するために HTML5 標準で定義されている API で、次のような特徴があります。
- 非同期 API: IndexedDB は、アクセスと操作に非同期 API を使用します。これにより、大量のデータ ストレージと大量の同時データ アクセスのニーズに適切に対処できます。
- 大規模データ ストレージ: IndexedDB は、大量の構造化データのストレージをサポートし、インデックス作成やトランザクション処理などの高度な操作をサポートしており、大規模データの高性能ローカル ストレージを必要とするシナリオに適しています。
- データベース クエリ: IndexedDB は、範囲クエリやカーソル クエリなどの複雑なクエリをサポートしており、開発者が正確なクエリと効率的なデータ取得を実行するのに役立ちます。
- データベース設計: IndexedDB 自体は、NoSQL に基づいたキーと値のストレージ データベースであり、他のデータベース (MongoDB など) と同様の設計概念を備えており、開発者が柔軟なデータベース設計とデータ モデル設計を実行するのに役立ちます。
他のブラウザ側ストレージ テクノロジと比較して、IndexedDB はクロスプラットフォーム互換性、セキュリティ、スケーラビリティに優れており、最新の Web アプリケーションのさまざまなデータ ストレージ要件を満たすことができます。ただし、その使用方法は複雑であるため、その利点を最大限に活用するには、開発者はブラウザ側のストレージ テクノロジ、JavaScript 非同期プログラミング、データベース設計、クエリについて深く理解する必要があります。