JavaScript 知识量:26 - 101 - 483
IndexedDB是一种在浏览器端存储大量结构化数据的底层API。它使用索引实现对数据的高性能搜索,可以存储和检索大量的数据,包括文件/二进制大型对象(blobs)。与Web Storage相比,IndexedDB适用于存储更大量的结构化数据。
IndexedDB是一种key-value型的数据库,value可以是复杂的结构体对象,而key可以是对象的某些属性值或其他对象(包括二进制对象)。可以使用对象中的任何属性作为index,以加快查找。
IndexedDB自带transaction,所有的数据库操作都会绑定到特定的事务上,并且这些事务是自动提交的。IndexedDB并不支持手动提交事务。大部分的IndexedDB API都是异步的,异步API的本质是向数据库发送一个操作请求,当操作完成的时候,会收到一个DOM event,通过该event,可以知道操作是否成功,并且获得操作的结果。
IndexedDB是一种NoSQL数据库,它存储的是Javascript对象。此外,IndexedDB还具有同源策略,每个源都会关联到不同的数据库集合,不同源是不允许访问其他源的数据库,从而保证了IndexedDB的安全性。
使用IndexedDB需要以下步骤:
打开数据库连接:使用indexedDB.open()方法打开数据库连接,该方法返回一个IDBRequest对象,可以通过该对象进行后续操作。
创建数据库:在打开数据库连接后,需要创建一个新的数据库,可以使用IDBDatabase对象来实现。可以通过传递一个数据库名称和版本号来创建数据库。
创建对象存储空间:在创建数据库后,需要创建一个或多个对象存储空间,可以使用IDBObjectStore对象来实现。可以通过传递一个存储空间名称、一个key path和是否允许重复键来确定存储空间的属性。
添加数据:可以使用IDBObjectStore.put()方法将数据添加到对象存储空间中。可以将一个或多个键值对作为参数传递给该方法。如果添加的数据已经存在,则会更新该数据。
获取数据:可以使用IDBObjectStore.get()方法从对象存储空间中获取数据。可以将一个键作为参数传递给该方法,并返回对应的值。
删除数据:可以使用IDBObjectStore.delete()方法从对象存储空间中删除数据。可以将一个键作为参数传递给该方法。
关闭数据库连接:在完成所有操作后,需要关闭数据库连接,可以使用IDBDatabase.close()方法来实现。
需要注意的是,IndexedDB是一个异步API,所有的操作都是异步进行的,需要使用回调函数或Promise来处理异步操作的结果。此外,IndexedDB的操作都是事务性的,每个操作都会绑定到一个事务中,事务的提交是自动进行的。
IndexedDB内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括JavaScript对象。在IndexedDB中,数据以"键值对"的形式保存在对象仓库中,每一个数据记录都有一个对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。
使用IndexedDB时,可以通过一个key作为索引进行存储或者获取数据。事务是IndexedDB中非常重要的概念,可以在事务中完成对数据的修改。IndexedDB支持事务,并且事务是自动提交的。
此外,IndexedDB还具有同源限制,每个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。IndexedDB的储存空间比LocalStorage大得多,一般来说不少于250MB,甚至没有上限。它不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer对象和Blob对象)。
IndexedDB是一个事务型数据库,它支持事务(transaction)。事务是操作数据库的一种方式,它可以将多个操作组合在一起,要么全部执行,要么全部不执行。在执行事务的过程中,如果有一步失败,整个事务就会被取消,数据库会进行回滚,回到事务发生前的状态。
在IndexedDB中,事务由IDBDatabase对象调用其transaction方法创建。该方法接受两个参数:storeNames和mode。storeNames参数是一个字符串数组,用于指明用户希望访问的objectStore。如果仅想访问一个objectStore,那么只需传入一个字符串而没必要传一个数组。为了避免性能下降,如果不是要对数据库写入数据就不要用readwrite模式打开事务。
在IndexedDB的事务中,如果存在一个不成功的事务,db属性的值会返回一个DOMException来指示错误对象。当事务尚未完成、完成了且成功提交或者是手动调用abort方法时,这个属性的值都为null。
IndexedDB的事务能确保数据的一致性和完整性,它通过原子性操作确保了在对数据库进行一系列操作时,如果没有错误发生,所有的操作都会被执行。如果发生错误,那么所有的操作都不会被执行,数据库会回滚到事务开始之前的状态。
IndexedDB 可以通过 add() 或 put() 方法将数据写入数据库。
add()方法:此方法创建一个新的数据库条目。如果已经存在具有相同键的条目,则此操作将失败并抛出异常。
put()方法:此方法更新现有的数据库条目。如果数据库中不存在具有相同键的条目,则此操作将创建一个新条目。
这两个方法都接受一个键/值对作为参数,其中键是用于唯一标识存储在数据库中的数据的主键,而值是要存储的实际数据。
例如,假设有一个名为“users”的对象存储空间,其中包含用户的姓名和年龄,可以使用以下代码将新用户添加到数据库中:
var request = indexedDB.open("myDatabase", 1); request.onerror = function(event) { // Handle errors }; request.onsuccess = function(event) { var db = request.result; db.onerror = function(event) { // Handle database errors }; var transaction = db.transaction(["users"], "readwrite"); var store = transaction.objectStore("users"); var newUser = { "name": "John", "age": 30 }; store.put(newUser, "newUserKey"); };
在这个例子中,首先打开一个名为“myDatabase”的数据库,并在打开成功后获取数据库对象。然后,创建一个包含用户名和年龄的对象,并使用 put() 方法将其添加到名为“users”的对象存储空间中,使用 "newUserKey" 作为键。
游标(Cursor)是用于在IndexedDB中查询数据的对象。游标允许按顺序遍历存储在数据库中的数据。以下是使用游标进行查询的基本步骤:
打开数据库连接并获取数据库对象。
创建一个事务对象,并传入想要操作的对象存储空间名称以及事务模式(读或读写)。
获取对象存储空间对象。
创建一个游标对象,通过调用openCursor()方法或者openKeyCursor()方法(如果只需要遍历键)并传入合适的范围和排序规则。
遍历游标对象,获取每个条目的数据和键。
在遍历过程中,可以通过advance()方法来控制遍历的步长。
关闭游标和事务,并关闭数据库连接。
以下是一个使用游标进行查询的示例代码:
// 打开数据库连接 var request = indexedDB.open("myDatabase", 1); // 处理错误 request.onerror = function(event) { // Handle errors }; // 处理成功打开数据库 request.onsuccess = function(event) { var db = request.result; // 创建一个名为“users”的对象存储空间 var transaction = db.transaction(["users"], "readonly"); var store = transaction.objectStore("users"); // 创建一个游标对象,获取所有用户数据并按年龄升序排序 var cursorRequest = store.openCursor(null, "prev"); // 处理游标事件 cursorRequest.onerror = function(event) { // Handle cursor error }; cursorRequest.onsuccess = function(event) { var cursor = cursorRequest.result; if (cursor) { // 获取当前条目的数据和键 var key = cursor.key; var value = cursor.value; console.log("Key: " + key + ", Value: " + value); // 继续遍历下一个条目 cursor.continue(); } else { // 遍历完成 } }; };
使用游标会给人一种不太理想的感觉,因为获取数据的方式受到了限制。使用键范围(key range)可以让游标更容易管理。键范围对应IDBKeyRange的实例。
IDBKeyRange是一个非常实用的工具,它可以通过定义一个键的范围来查询数据库。通过使用IDBKeyRange,可以查询特定范围内的所有数据,或者在特定键上执行更复杂的查询。
IDBKeyRange有四个静态方法:
IDBKeyRange.lowerBound(lower): 这个方法返回一个新的IDBKeyRange实例,该实例表示一个键值大于或等于lower的范围。
IDBKeyRange.upperBound(upper): 这个方法返回一个新的IDBKeyRange实例,该实例表示一个键值小于或等于upper的范围。
IDBKeyRange.bound(lower, upper): 这个方法返回一个新的IDBKeyRange实例,该实例表示一个键值在lower和upper之间的范围。
IDBKeyRange.only(value): 这个方法返回一个新的IDBKeyRange实例,该实例表示一个键值等于value的范围。
这些方法都很有用,特别是想要在数据库中查询特定范围的数据时。例如,可能想要获取所有在特定日期之后添加的条目,或者获取所有在特定日期范围内添加的条目。使用IDBKeyRange可以更精确地控制查询,从而获取到需要的数据。
openCursor() 方法是 IndexedDB API 的一部分,用于打开一个游标以在数据库中遍历数据。然而,至 2021 年为止,IndexedDB API 并没有直接设置游标方向的方法。游标默认从数据库的起始位置开始,并按照数据库的默认排序规则进行遍历。
可以通过在 openCursor() 方法中传递不同的 direction 参数来改变遍历的方向。然而,至 2021 年为止,IndexedDB 只支持按升序或降序遍历,所以 direction 参数只能设置为 'next'(按升序向后遍历)、'prev'(按降序向前遍历)或 'nextunique'(按升序向前遍历,跳过已经遍历过的键)。
这是一个使用 openCursor() 方法并设置遍历方向的例子:
var transaction = db.transaction(['myStore'], 'readonly'); var store = transaction.objectStore('myStore'); var keyRange = IDBKeyRange.bound('lower', 'upper'); // 设置键的范围 var direction = 'next'; // 设置遍历方向 var cursorRequest = store.openCursor(keyRange, direction); cursorRequest.onsuccess = function(event) { var cursor = cursorRequest.result; if (cursor) { // 处理获取到的数据 console.log(cursor.value); cursor.continue(); // 继续遍历 } else { // 遍历完成 } }
createIndex() 方法在 IndexedDB 中用于创建一个新的索引。索引是在数据库中存储和检索数据的一种方式。通过索引,可以根据指定的列的值快速查找和访问数据。
以下是 createIndex() 方法的基本语法:
var request = indexedDB.createIndex(databaseName, objectStoreName, indexName, keyPath, optionalParameters);
简要说明如下:
databaseName:要创建索引的数据库的名称。
objectStoreName:要在其中创建索引的对象存储的名称。
indexName:新索引的名称。
keyPath:指定用作索引键的值或路径。这是将要索引的数据列的路径。
optionalParameters:可选参数,用于定义索引的其他属性。例如,可以指定是否唯一索引,是否在后台线程中创建索引等。
以下是一个简单的示例,展示如何使用 createIndex() 方法在名为 "users" 的对象存储中创建一个名为 "username" 的索引:
var openRequest = indexedDB.open("myDatabase", 1); openRequest.onerror = function(event) { // Handle errors }; openRequest.onsuccess = function(event) { var db = openRequest.result; var transaction = db.transaction("users", "readwrite"); var store = transaction.objectStore("users"); store.createIndex("username", "username"); };
在上面的示例中,首先打开名为 "myDatabase" 的数据库,并在成功打开后获取了数据库对象。然后,创建一个名为 "username" 的索引,该索引在 "username" 列上。通过使用 createIndex() 方法,现在可以在数据库中根据用户名进行快速检索。
IndexedDB 有一些限制和约束,包括以下几点:
同源限制:IndexedDB 受到同源限制,每个数据库对应创建它们的域名。网页只能访问自身名下的数据库,而不能访问跨域的数据库。
存储空间:虽然具体的存储空间大小因浏览器和设备而异,但 IndexedDB 的存储空间通常较大,可以达到几百兆甚至更多。然而,这也意味着使用 IndexedDB 存储大量数据可能会占用较多的内存和存储空间。
数据类型:IndexedDB 可以存储多种类型的数据,包括字符串、二进制数据、日期和时间戳等。然而,对于一些特定类型的数据,如 ArrayBuffer 对象或 Blob 对象,IndexedDB 只允许以二进制形式存储。
事务处理:IndexedDB 采用事务处理方式,对于每个操作都必须是原子性操作,这可能会导致在处理大量数据时性能下降。此外,事务处理也受到浏览器页面的生命周期和可用内存的限制。
并发访问:IndexedDB 不支持并发访问。如果多个事务同时尝试访问同一数据,将会导致数据竞争和可能的冲突。
查询能力:IndexedDB 的查询能力有限,主要依赖于索引和游标。虽然可以创建多键索引来提高查询性能,但相对于其他数据库系统(如 MySQL 或 PostgreSQL),其查询功能可能不够强大。
浏览器兼容性:虽然大多数现代浏览器都支持 IndexedDB,但不同浏览器之间的兼容性可能会有所差异。在使用 IndexedDB 时,需要考虑不同浏览器的兼容性问题。
Copyright © 2017-Now pnotes.cn. All Rights Reserved.
编程学习笔记 保留所有权利
MARK:3.0.0.20240214.P35
From 2017.2.6