浏览器存储--IndexedDB数据库的使用


前言

IndexedDB是一个事务数据库系统,类似于基于SQL的RDBMS。然而,与使用固定列表的基于SQL的RDBMS不同,IndexedDB是一个基于JavaScript的面向对象数据库。

为啥要使用呢?

随着浏览器的功能不断增强,越来越多的网站开始考虑,将大量数据储存在客户端,这样可以减少从服务器获取数据,直接从本地获取数据。

现有的浏览器数据储存方案,都不适合储存大量数据:Cookie 的大小不超过4KB,且每次请求都会发送回服务器;localStorage 和 sessionStorage 在 2.5MB 到 10MB 之间(各家浏览器不同),而且不提供搜索功能,不能建立自定义的索引。所以,需要一种新的解决方案,这就是 IndexedDB 诞生的背景。


一、IndexedDB是什么?

通俗地说,IndexedDB 就是浏览器提供的本地数据库,它可以被网页脚本创建和操作。IndexedDB 允许储存大量数据,提供查找接口,还能建立索引。这些都是 LocalStorage 所不具备的。就数据库类型而言,IndexedDB 不属于关系型数据库(不支持 SQL 查询语句),更接近 NoSQL 数据库。

IndexedDB 具有以下特点。

  • 键值对储存。 IndexedDB 内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 JavaScript 对象。对象仓库中,数据以"键值对"的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。

  • 异步。 IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage 形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。

  • 支持事务。 IndexedDB 支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。

  • 同源限制 IndexedDB 受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。

  • 储存空间大 IndexedDB 的储存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有上限。

  • 支持二进制储存。 IndexedDB 不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer 对象和 Blob 对象)。

更多详细的介绍可移步这里查看

二、使用步骤

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

添加的时候需要注意添加对象内的key是否有存在于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() 打开数据库

在这里插入图片描述

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
IndexedDB浏览器提供的本地数据库,可以在浏览器存储结构化数据。下面是 IndexedDB 的基本使用方法: 1. 打开数据库 使用 `indexedDB` 对象的 `open()` 方法打开数据库,如下所示: ``` let request = indexedDB.open('myDB', 1); ``` 其中,第一个参数是数据库名称,第二个参数是数据库版本号。如果数据库不存在,则会创建一个新的数据库。 2. 创建对象仓库 在成功打开数据库的回调方法 `request.onsuccess` 中,可以获取到数据库对象 `event.target.result`,然后使用它的 `createObjectStore()` 方法创建一个对象仓库(即数据表),如下所示: ``` let db = event.target.result; let objectStore = db.createObjectStore('people', { keyPath: 'id' }); ``` 其中,第一个参数是对象仓库的名称,第二个参数是一个对象,包含一个 keyPath 属性和其他可选属性。keyPath 用来指定数据表中的主键。 3. 添加数据 使用事务 `db.transaction()` 开启一个事务,然后使用 `add()` 方法向数据表中添加数据,如下所示: ``` let transaction = db.transaction(['people'], 'readwrite'); let objectStore = transaction.objectStore('people'); let request = objectStore.add({ id: 1, name: 'John Doe' }); ``` 其中,第一个参数是一个数组,包含要访问的对象仓库的名称,第二个参数是事务类型,可以是 'readonly' 或 'readwrite'。`add()` 方法的参数是要添加的数据。 4. 查询数据 使用事务 `db.transaction()` 开启一个事务,然后使用 `get()` 方法查询数据,如下所示: ``` let transaction = db.transaction(['people']); let objectStore = transaction.objectStore('people'); let request = objectStore.get(1); request.onsuccess = function(event) { console.log('Name: ' + event.target.result.name); }; ``` `get()` 方法的参数是要查询的数据的主键值。查询结果保存在 `request.onsuccess` 回调方法中的 `event.target.result` 中。 5. 更新数据 使用事务 `db.transaction()` 开启一个事务,然后使用 `put()` 方法更新数据,如下所示: ``` let transaction = db.transaction(['people'], 'readwrite'); let objectStore = transaction.objectStore('people'); let request = objectStore.put({ id: 1, name: 'Jane Doe' }); ``` `put()` 方法的参数是要更新的数据。 6. 删除数据 使用事务 `db.transaction()` 开启一个事务,然后使用 `delete()` 方法删除数据,如下所示: ``` let transaction = db.transaction(['people'], 'readwrite'); let objectStore = transaction.objectStore('people'); let request = objectStore.delete(1); ``` `delete()` 方法的参数是要删除的数据的主键值。 以上就是 IndexedDB 的基本使用方法。需要注意的是,IndexedDB 的 API 非常庞大,不仅仅包含上面提到的这些方法,还包括索引、游标、版本升级等功能。如果需要更详细的介绍和示例代码,可以参考 MDN 的文档:https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值