ブラウザストレージ -- IndexedDB データベースの使用


序文

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()

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/weiCong_Ling/article/details/131437456