Browser storage--Use of IndexedDB database


foreword

IndexedDB is a transactional database system, similar to SQL-based RDBMS. However, unlike SQL-based RDBMSs that use fixed lists, IndexedDB is a JavaScript-based object-oriented database.

Why use it?

As the functionality of browsers continues to increase, more and more websites are beginning to consider storing a large amount of data on the client, which can reduce the need to obtain data from the server and directly obtain data from the local.

Existing browser data storage solutions are not suitable for storing large amounts of data: the size of the cookie does not exceed 4KB, and each request will be sent back to the server; localStorage and sessionStorage are between 2.5MB and 10MB (different for each browser), And it does not provide a search function, and cannot create a custom index. Therefore, a new solution is needed, which is the background of the birth of IndexedDB.


1. What is IndexedDB?

In layman's terms, IndexedDB is a local database provided by the browser, which can be created and manipulated by web scripts. IndexedDB allows storing large amounts of data, providing a lookup interface, and building indexes. These are not available in LocalStorage. As far as the database type is concerned, IndexedDB is not a relational database (does not support SQL query statements), but is closer to a NoSQL database.

IndexedDB has the following characteristics.

  • Key-value pair storage. IndexedDB internally uses an object store (object store) to store data. All types of data can be stored directly, including JavaScript objects. In the object warehouse, data is stored in the form of "key-value pairs". Each data record has a corresponding primary key. The primary key is unique and cannot be duplicated, otherwise an error will be thrown.

  • asynchronous. IndexedDB will not lock the browser during operation, and users can still perform other operations. This is in contrast to LocalStorage, whose operations are synchronous. The asynchronous design is to prevent the reading and writing of large amounts of data and slow down the performance of web pages.

  • Support transactions. IndexedDB supports transactions, which means that as long as one step fails in a series of operation steps, the entire transaction will be cancelled, and the database will be rolled back to the state before the transaction occurred, and there will be no situation where only part of the data is rewritten.

  • Same-origin restriction IndexedDB is subject to the same-origin restriction, and each database corresponds to the domain name where it was created. A webpage can only access databases under its own domain name, but not cross-domain databases.

  • Large storage space The storage space of IndexedDB is much larger than that of LocalStorage, generally not less than 250MB, and there is even no upper limit.

  • Binary storage is supported. IndexedDB can store not only strings, but also binary data (ArrayBuffer objects and Blob objects).

More detailed introduction can be viewed here

2. Use steps

1. Encapsulate common methods (creating constructors)

Modular development is an essential front-end skill. Let’s simply encapsulate a IndexDBCacheclass for adding, deleting, modifying, and checking operations.

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. Instantiate and perform various operations

Initialize the database

// 根据项目实际需求,设置对应数据库名、表名和数据库主键(主键需要为添加对象内的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)
	})
}

insert image description here

adding data

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

When adding, you need to pay attention to whether the key in the added object exists in the keyPath. If not, adding new data will cause failure, as shown in the figure below
insert image description here

delete data

  • Delete the specified primary key value
const removeIndexDB = () => {
    
    
	imageDB.remove('uploadImgName42424198')
}

Original data
insert image description here
after deletion
insert image description here

  • Clear database data
const clearIndexDB = () => {
    
    
	imageDB.clearDB()
}

update data

The current example assumes imageNamethe primary key

const updateIndexDB = () => {
    
    
	imageDB.update({
    
    
		imageData: "uploadImgUrl",
		imageFile: "uploadFile",
		imageName: "uploadImgName33027705"
	})
}

Query data

  • Get data by primary key
// 从数据库获取数据
// imageName 可为空或者 null,即返回所有数据否则是指定key对应的值
const getImageByName = (imageName) => {
    
    
	imageDB.getDataByKey(imageName).then((res) => {
    
    
		console.log('从indexDB数据库获取数据成功', res)
	}).catch((err) => {
    
    
		console.log('从indexDB数据库获取数据失败==>', err)
	})
}

insert image description here

  • Get data by index
const getDataByIndexDB = () => {
    
    
	imageDB.getDataByIndex({
    
    
		index: 'imageData',
		value: 'uploadImgUrl57913099'
	})
}

insert image description here

close database

const closeIndexDB = () => {
    
    
	imageDB.closeDB()
}

As shown in the figure below, after closing the database, if you get the data again, it will prompt that the database is closed. If you need to get the data again after closing, you need to imageDB.initDB()open the database

insert image description here

Guess you like

Origin blog.csdn.net/weiCong_Ling/article/details/131437456