記事ディレクトリ
序文
IndexedDB は、SQL ベースの RDBMS に似たトランザクション データベース システムです。ただし、固定リストを使用する SQL ベースの RDBMS とは異なり、IndexedDB は JavaScript ベースのオブジェクト指向データベースです。
なぜそれを使うのでしょうか?
ブラウザの機能が向上し続けるにつれて、ますます多くの Web サイトがクライアントに大量のデータを保存することを検討し始めています。これにより、サーバーからデータを取得する必要性が減り、ローカルから直接データを取得できるようになります。
既存のブラウザ データ ストレージ ソリューションは、大量のデータの保存には適していません。Cookie のサイズは 4KB を超えず、各リクエストはサーバーに送り返されます。localStorage と sessionStorage は 2.5MB ~ 10MB です (ブラウザごとに異なります)。 )、検索機能は提供されておらず、カスタムインデックスを作成することもできません。したがって、新しいソリューションが必要になったのが IndexedDB 誕生の背景です。
1. IndexedDB とは何ですか?
平たく言えば、IndexedDB はブラウザによって提供されるローカル データベースであり、Web スクリプトによって作成および操作できます。IndexedDB を使用すると、大量のデータを保存し、検索インターフェイスを提供し、インデックスを構築できます。これらは LocalStorage では使用できません。データベースの種類に関する限り、IndexedDB はリレーショナル データベースではありません (SQL クエリ ステートメントをサポートしません) が、NoSQL データベースに近いものです。
IndexedDB には以下の特徴があります。
-
キーと値のペアのストレージ。IndexedDB は内部でオブジェクト ストア (オブジェクト ストア) を使用してデータを保存します。JavaScript オブジェクトを含むすべてのタイプのデータを直接保存できます。オブジェクト ウェアハウスでは、データは「キーと値のペア」の形式で保存されます。各データ レコードには、対応する主キーがあります。主キーは一意であり、重複することはできません。重複しない場合は、エラーがスローされます。
-
非同期。IndexedDB は動作中にブラウザをロックせず、ユーザーは他の操作を実行できますが、これは、動作が同期である LocalStorage とは対照的です。非同期設計は、大量のデータの読み取りと書き込みを防止し、Web ページのパフォーマンスを低下させることを目的としています。
-
トランザクションをサポートします。IndexedDB はトランザクションをサポートしています。つまり、一連の操作ステップのうち 1 つのステップが失敗した限り、トランザクション全体がキャンセルされ、データベースはトランザクションが発生する前の状態にロールバックされ、トランザクションだけが失敗するという状況は発生しません。データの一部が書き換えられます。
-
同一オリジンの制限 IndexedDB には同一オリジンの制限が適用され、各データベースは作成されたドメイン名に対応します。Web ページは、独自のドメイン名のデータベースにのみアクセスできますが、クロスドメイン データベースにはアクセスできません。
-
大容量のストレージ スペース IndexedDB のストレージ スペースは LocalStorage のストレージ スペースよりもはるかに大きく、通常は 250MB 以上であり、上限もありません。
-
バイナリストレージがサポートされています。IndexedDB は文字列だけでなく、バイナリ データ (ArrayBuffer オブジェクトや Blob オブジェクト) も格納できます。
詳しい紹介はこちらからご覧いただけます
2. ステップを使用する
1. 共通メソッドのカプセル化 (コンストラクターの作成)
モジュール開発は重要なフロントエンド スキルです。IndexDBCache
追加、削除、変更、操作を確認するためのクラスを単純にカプセル化してみましょう。
const indexDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB;
export class IndexDBCache {
constructor(
params = {
dbName: "test", // 数据库名
cacheTableName: "imageCache", // 表名
keyPath: "imageName", // 设置主键 (需要为添加对象内的key,否则新增和获取都会失败)
indexs: [], // 设置索引
}
) {
this._db = null; // 数据库
this._transaction = null; // 事务
this._request = null; // 打开数据库返回的事务
this._dbName = params.dbName; // 数据库名
this._cacheTableName = params.cacheTableName; // 表名
this._dbversion = 1; // 数据库版本
this._keyPath = params.keyPath; // 设置主键
this._indexs = params.indexs; // 设置索引
}
// 初始化数据库
initDB() {
return new Promise((resolve, reject) => {
// 打开数据库
this._request = indexDB.open(this._dbName, this._dbversion);
// 数据库初始化成功
this._request.onsuccess = (event) => {
this._db = this._request.result;
resolve(event);
};
// 数据库初始化失败
this._request.onerror = (event) => {
reject(event);
};
// 数据库初次创建或更新时(指定的版本号,大于数据库的实际版本号)会触发
this._request.onupgradeneeded = (event) => {
// 这时通过事件对象的target.result属性,拿到数据库实例。
const db = event.target.result;
if (!db.objectStoreNames.contains(this._cacheTableName)) {
const objectStore = db.createObjectStore(this._cacheTableName, {
keyPath: this._keyPath,
});
this._index.forEach(element => {
// 三个参数分别为索引名称、索引所在的属性、配置对象(说明该属性是否包含重复的值)
objectStore.createIndex(element.name, element.name, {
unique: element.unique });
});
}
resolve(event);
};
});
}
/**
* @description : 新增数据
* @param {Object} params 添加到数据库中的数据 { imageName: 文件名, image: base64格式图片 }
* @return {*}
*/
addData(params) {
return new Promise((resolve, reject) => {
const transaction = this._db.transaction(
this._cacheTableName,
"readwrite"
);
const store = transaction.objectStore(this._cacheTableName);
const response = store.add(params);
response.onsuccess = (event) => {
resolve(event);
};
response.onerror = (event) => {
reject(event);
};
});
}
// 删除指定主键值
remove(key) {
var request = this._db.transaction([this._cacheTableName], 'readwrite')
.objectStore(this._cacheTableName)
.delete(key);
request.onsuccess = function (event) {
console.log('数据删除成功');
};
}
// 清空数据库数据
clearDB() {
return new Promise((resolve, reject) => {
const transaction = this._db.transaction(
this._cacheTableName,
"readwrite"
);
const store = transaction.objectStore(this._cacheTableName);
const response = store.clear();
response.onsuccss = (event) => {
resolve(event);
};
response.onerror = (event) => {
reject(event);
};
});
}
// 通过主键读取数据
getDataByKey(key) {
return new Promise((resolve, reject) => {
const transaction = this._db.transaction(this._cacheTableName);
const objectStore = transaction.objectStore(this._cacheTableName);
// 通过主键读取数据
// const request = objectStore.get(key);
// getAll(key)同get(key)获取指定key对应数据,如果getAll不传参或者传null即返回所有数据
const request = objectStore.getAll(key);
request.onsuccess = () => {
resolve(request.result);
};
request.onerror = (event) => {
reject(event);
};
});
}
// 通过主键读取数据
getDataByIndex(params) {
const transaction = this._db.transaction([this._cacheTableName], 'readonly');
const store = transaction.objectStore(this._cacheTableName);
const index = store.index(params.index);
const request = index.get(params.value);
request.onsuccess = function (e) {
const result = e.target.result;
console.log('getDataByIndex', result)
}
}
}
// 遍历数据
readAll() {
const objectStore = this._db.transaction(this._cacheTableName).objectStore(this._cacheTableName);
objectStore.openCursor().onsuccess = function (event) {
const cursor = event.target.result;
if (cursor) {
console.log('key: ' + cursor.key);
console.log('Value: ' + JSON.stringify(cursor.value));
cursor.continue();
} else {
console.log('没有更多数据了!');
}
};
}
// 更新指定主键数据
update(params) {
var request = this._db.transaction([this._cacheTableName], 'readwrite')
.objectStore(this._cacheTableName)
.put(params);
request.onsuccess = function (event) {
console.log('数据更新成功');
};
request.onerror = function (event) {
console.log('数据更新失败');
}
}
// 关闭数据库
closeDB() {
this._db.close();
}
// 删除数据库
deleteDB() {
console.log('开始删除数据库')
let DBDeleteRequest = indexDB.deleteDatabase(this._dbName)
DBDeleteRequest.onsuccess = function (event) {
console.log('删除数据库成功')
}
DBDeleteRequest.onerror = function (event) {
console.log('删除数据库失败')
}
}
}
2. インスタンスを作成してさまざまな操作を実行する
データベースを初期化する
// 根据项目实际需求,设置对应数据库名、表名和数据库主键(主键需要为添加对象内的key,否则新增和获取会失败)
const params = {
dbName: "test",
cacheTableName: "imageCache",
keyPath: "imageName",
indexs: [
{
name: 'imageData', unique: false},
{
name: 'imageFile', unique: true}
]
}
let imageDB = new IndexDBCache(params)
const initIndexDB = () => {
imageDB.initDB().then(res => {
if (res.type == 'upgradeneeded') {
console.log('indexDB 数据库创建或更新成功!')
} else {
console.log('indexDB 数据库初始化成功!')
}
}).catch((err) => {
console.log('indexDB 数据库初始化失败! ', err)
})
}
データの追加
function RandomNumber() {
return Math.floor(Math.random() * 100000000.0)
}
const changeVal = () => {
const data = {
imageName: 'uploadImgName' + RandomNumber(), imageData: 'uploadImgUrl' + RandomNumber(), imageFile: 'uploadFile' + RandomNumber() }
imageDB.addData(data).then((res) => {
console.log('写入 indexDB 数据库成功', res)
}).catch((err) => {
console.log('写入 indexDB 数据库失败==>', err)
})
}
追加する際は、追加したオブジェクトのキーがkeyPathに存在するかどうかに注意する必要があり、存在しない場合、下図のように新規データの追加が失敗します。
データを削除する
- 指定された主キー値を削除します
const removeIndexDB = () => {
imageDB.remove('uploadImgName42424198')
}
削除後の元データ
- データベースデータをクリアする
const clearIndexDB = () => {
imageDB.clearDB()
}
データを更新する
現在の例ではimageName
主キーを想定しています。
const updateIndexDB = () => {
imageDB.update({
imageData: "uploadImgUrl",
imageFile: "uploadFile",
imageName: "uploadImgName33027705"
})
}
クエリデータ
- 主キーでデータを取得する
// 从数据库获取数据
// imageName 可为空或者 null,即返回所有数据否则是指定key对应的值
const getImageByName = (imageName) => {
imageDB.getDataByKey(imageName).then((res) => {
console.log('从indexDB数据库获取数据成功', res)
}).catch((err) => {
console.log('从indexDB数据库获取数据失败==>', err)
})
}
- インデックスによるデータの取得
const getDataByIndexDB = () => {
imageDB.getDataByIndex({
index: 'imageData',
value: 'uploadImgUrl57913099'
})
}
データベースを閉じる
const closeIndexDB = () => {
imageDB.closeDB()
}
下図のように、データベースを閉じた後、再度データを取得すると、データベースを閉じる旨のメッセージが表示されますので、閉じた後に再度データを取得する必要がある場合は、データベースを開く必要がありますimageDB.initDB()
。