Indexeddb 简明教程
IndexedDB - Introduction
数据库管理系统提供了一种存储和检索数据的方法。有各种类型的数据库可以使用,其中最常用的有 -
-
Hierarchical databases
-
Network databases
-
Object-oriented databases
-
Relational databases
-
NoSQL databases
NoSQL databases
NoSQL 数据库(有时称为非 SQL)是一种提供存储和检索数据的方法的数据库,而不是关系数据库中使用的表格关系。这些数据库是无模式的,支持轻松复制,具有简单的 API,最终一致,并且可以处理大量数据(大数据)。
还有不同类型的 NoSQL 数据库,例如 -
-
Document databases.
-
Key-value stores. Column-oriented databases. Graph databases.
What is IndexedDB
Indexed Database 是一种 NoSQL 数据库或非关系结构化查询语言。它是一个事务数据库系统,类似基于 SQL 的 RDBMS。但是,与使用固定列表的基于 SQL 的 RDBMS 不同,IndexedDB 是基于 JavaScript 面向对象数据库。
当我们需要在服务器端存储大量数据并且比本地存储更快时,就会使用它。由于它将数据存储在浏览器中,因此也可以在线和离线使用。使用此功能,您可以创建一个 Web 应用程序(具有丰富的查询功能),无论是否有互联网连接都可以运行。
Key Characteristics of IndexedDB
以下是 IndexedDB 数据库的主要特征 -
IndexedDB 是一个 NoSQL 数据库,存储键值对。它可以通过键或多种键类型存储几乎任何类型的值。
-
As mentioned, IndexedDB follows a transactional database model - 事务是操作或操作组周围的包装类,以便维护数据完整性。您不希望数据被更改或遗漏,因此如果事务失败,则会推出回调。
-
IndexedDB does not use Structured Query Language - 由于 IndexedDB 使用 NoSQL 数据库,它不使用 SQL,而是使用索引上的查询通过光标或 getAll() 方法在不同的集合中进行遍历来生成数据。
-
IndexedDB uses a lot of requests - 请求是接收成功或失败的 DOM 事件的对象(DOM - HTML DOM 事件允许 JavaScript 在 HTML 文档中的元素上注册不同的事件处理程序)。DOM 事件是成功或错误,具有指示请求流的 target 属性。成功事件无法取消,但错误事件可以取消。IndexedDB 中有许多请求,例如 on success、 onerror 和 addEventListener() ,以及 removeEventListener()。为了知道请求的状态,我们还有 ready state、result 和 error code 属性。
-
IndexedDB needs to follow the same origin - 来源是编写脚本的文档的 URL,每个来源下面有一些数据库,每个数据库都有其名称,可由该来源标识。施加在 IndexedDB 上的安全边界阻止应用程序访问具有不同来源的数据。例如,如果我们使用 URL 并获取其不同的子目录,它可以检索数据,但如果我们更改位置到端口 8080 并尝试从常用 URL 和更改的端口检索数据,则无法检索数据。
Terminology
以下是 IndexedDB 中重要的各种术语,在继续之前你应该了解这些术语:
-
Database - 在 IndexedDB 数据库中,数据库是最高级别,包含存储包含数据的对象存储。
-
Object Stores - 对象存储是 IndexedDB 的数据存储实体。可以将它们视为 RDBMS 中的表,我们根据要存储的数据类型来存储数据(例如:id、name、roll no 等)。
-
Transaction - 对于任何数据库操作,我们执行以下过程。获取数据库对象,对数据库执行打开事务,对事务执行打开对象存储,然后对对象存储进行操作。因此,基本上,事务是连接到每个数据库的包装函数,它确保数据完整性,以便在事务取消或发生任何错误时,它将回调到尚未开始的事务。
-
Index - 将对象存储视为一个表,我们使用索引从它们中检索单个属性的数据。例如:名称、年龄等。
-
Cursor - 在数据库中,如果我们需要从对象存储中遍历多个记录,则使用光标。
Support for IndexedDB
IndexedDB 是浏览器中的数据库,因此我们需要检查它是否受当前/现有浏览器支持。为此,请将以下代码粘贴到文本编辑器中,将其另存为 test.html ,并在浏览器中运行它。
const indexedDB =
window.indexedDB ||
window.mozIndexedDB ||
window.webkitIndexedDB ||
window.msIndexedDB ||
window.shimIndexedDB;
if (!indexedDB) {
document.write("IndexedDB could not be found in this browser.");
}
const request = indexedDB.open("MyDatabase", 1);
如果你的浏览器支持 IndexedDB,此程序将成功执行,并且将创建数据库。
IndexedDB - Installation
Visual Studio Code 是重新定义并针对构建和调试现代 Web 和云应用程序而优化过的代码编辑器。
-
你可以从其官方网站 https://code.visualstudio.com 下载 Visual Studio Code。
-
根据 PC 配置和 OS 选择你想要的版本。
-
下载后,你可以直接在计算机上安装它。
Installing the Visual Studio Code installer on Windows
首先,按照上述说明下载适用于 Windows 的 Visual Studio Code 安装程序:
-
下载后,运行安装程序。
-
然后,接受协议并单击 next。
-
现在,单击 “create a desktop icon” ,以便可以从桌面访问它,并单击 Next。
-
然后,点击安装按钮。
-
最后,在安装完成后,单击完成按钮,Visual Studio code 将打开。
-
Visual Studio code 已成功安装到你的设备上了,现在你可以开始在这个代码编辑器上编写代码了。
Downloading, Installing, and Creating a Node.js project (optional)
现在,在安装 Visual Studio code 后,我们需要安装 Node.js
Downloading Node.JS
-
你可以从其官网下载 Node.js,网址是 [role="bare"] [role="bare"]https://nodejs.org/en/ 。
-
基于你的计算机配置,选择你需要的版本。
-
我们建议使用 LTS 版本,因为它是比较稳定的版本,并且它代表长期支持。
Installing Node.js
按照以下步骤在系统中安装 Node.js:
Step 1 - 在 Node.js 打开后。你会发现这个窗口弹出。点击下一步。
Step 2 - 你将被重定向到 “End-User License Agreement” 窗口。接受协议并点击 @[s4}。
Step 3 - 在下一个窗口中,你需要选择 “ Destination Folder ”。更改现有文件夹或使用提及的默认文件夹,然后点击 Next 。
Step 4 - 在 “ Custom Setup ” 和 “ Tools For Native Modules ” 中点击 Next 。
Step 5 - 现在,安装设置已就绪,点击 Install ,以安装所选模块。
IndexedDB - Connection
数据库是一个有序的、结构化数据集合,这些数据存储在计算机系统中。为了对数据执行操作,我们需要连接到数据库。在本章中,我们将讨论如何创建/连接到数据库、打开数据库和删除数据库。
Creating a database - 你可以使用 open() 函数在 IndexedDB 中创建一个数据库。以下是此函数的语法。
let openRequest = indexedDB.open(name, version);
其中,
-
name 是你要创建的数据库的名称。
-
version 是要创建的数据库的版本。此参数的默认值为 1。如果你省略此值,则版本将被视作 1。
你要传递给此函数的版本值不应低于当前版本(IndexedDB 的版本)。如果成功创建了数据库,则此函数返回 1;如果创建失败,则返货 0。
Example
以下是 IndexedDB 中创建数据库的示例:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Indexed db</title>
</head>
<body>
<script>
//Creating a database
const request = indexedDB.open("myDatabase", 1);
if(indexedDB){
document.write("Database Created......");
}
</script>
</body>
</html>
Verification
因为 IndexedDB 是浏览器内置的数据库,所以在浏览器中就能看到创建的数据库。
右键点击生成页面,点击“检查元素”并选取“应用标签”。如果展开此选项卡,您可以在其中看到 IndexedDB 数据库,您可以看到创建的数据库文件,如下所示:
Generating Handlers
event 是在 HTML 元素上执行的操作。我们可以使用 JavaScript 处理这些事件。从现在开始,我们将使用 JavaScript 处理程序(为了让此更清楚)。
如果请求成功,我们将使用 onsuccess 事件。
request.onerror = event => {
// Do something (ex: document.write("error");
};
如果请求失败,我们将使用 onerror 事件。
request.onsuccess = event => {
// Do something (ex : document.write("success");
};
当创建一个数据库或增加现有数据库的版本号时,我们将使用 onupgradeneeded 事件。
request.onupgradeneeded = event => {
var db = event.target.result;
};
Example
以下示例显示消息“ database creation success ”。如果数据库创建成功。在这里,我们使用 onsuccess 和 onerror 处理程序来显示这些消息。
<!DOCTYPE html>
<html lang="en">
<head>
<title>Handlers</title>
</head>
<body>
<script>
const request = indexedDB.open("DATABASE", 1);
request.onsuccess = function (){
document.write("Database created successfully...")
}
request.onerror = function(){
document.write("database creation error");
}
request.onupgradeneeded = function(event){
var db = event.target.result;
}
</script>
</body>
</html>
Connecting to an existing database
为了与 IndexedDB 交互,我们使用 JavaScript。我们用 JavaScript 撰写的代码并不会直接与数据库交互。我们需要使用连接对象连接到数据库,以操作数据库的对象。
直接打开数据库会创建一个连接。一个数据库可以有多个连接。当创建连接之初,它处于打开状态。
您可以使用 open() 函数连接到 IndexedDB 数据库(我们用来创建数据库)。
Example
下面给出了一个使用带有连接对象的 JavaScript 示例,它与现有数据库交互:
<!DOCTYPE html>
<html lang="en">
<head>
<title>OPENING A DATABASE</title>
</head>
<body>
<script>
const request = indexedDB.open("DATABASE", 1);
request.onsuccess = function (){
document.write("<br> Database created successfully")
}
const requestone = indexedDB.open("Database1",2);
requestone.onsuccess = function(){
document.write("<br> Database created successfully");
}
const requesttwo = indexedDB.open("DATABASE",1);
requesttwo.onsuccess = function(){
document.write("<br> Database opened successfully");
}
</script>
</body>
</html>
Another way to check databases in the browser
除了检查元素之外,还有另一种方法可以在浏览器中检查 IndexedDB 数据库。
在右上角将有一个“自定义和控制”按钮,点击它。
在列表中选择 More tools 选项,然后选择 Developer tools 。
在下一页中选择“应用程序”选项卡,您可以在其中看到 IndexedDB 数据库。
Deleting a database
如果有我们不需要的或没有必要占用空间的任何数据库,我们可以将其删除。要删除数据库,我们可以使用 deleteDatabase() 函数。
以下是 deleteDatabase() 函数的语法 −
let deleteRequest = indexedDB.deleteDatabase(name)
这里, name 参数是我们想要删除的数据库的名称。
Example
以下示例创建了一个名为 TestDatabase 的数据库并使用 deleteDatabase() 函数将其删除。
<!DOCTYPE html>
<html lang="en">
<head>
<title>Indexed db</title>
</head>
<body>
<script>
const request = indexedDB.open("TestDatabase", 1);
request.onsuccess = function () {
document.write("Database Created Successfully");
};
var req = indexedDB.deleteDatabase("TestDatabase");
req.onsuccess = function () {
document.write("Database Deleted Successfully");
};
req.onerror = function () {
document.write("Couldn't delete the database");
};
</script>
</body>
</html>
Deleting a database Directly From the browser
创建数据库后,您可以直接从浏览器中删除它。要执行此操作,请按照以下步骤操作 −
Step 1 − 使用以下方式之一在浏览器中打开可以看到 IndexedDB 数据库(存储)的页面
-
Inspect option − 鼠标右键单击 → 检查 → 应用程序,或
-
Developer tools − 自定义和控制选项 → 更多工具 → 开发者工具 → 应用程序
Step 2 − 如果您展开 IndexedDB 存储,可以看到如下图所示的已创建数据库列表。
Step 3 − 单击要删除的数据库。在右侧,您将找到 Delete Database 按钮。如果单击它,将删除此数据库。
IndexedDB - Object Stores
Object stores 是 IndexedDB 的数据存储。这是存储数据的地方。数据库可以包含多个对象存储。可以将它们视为 RDBMS 中的表,在其中我们根据想要存储的数据类型存储数据。
为了确保数据库完整性,只能使用回调函数 idb.open() 来创建和删除对象存储。它包含一个名为 createObjectStore() 的方法,用于创建对象存储。
Creating object Stores
可以使用 createObjectStore() 方法来创建对象存储。以下是此方法的语法 −
IDBDatabase.createObjectStore(name);
Or,
IDBDatabase.createObjectStore(name, options);
其中,
-
name 是对象存储的名称。
-
options 对象允许我们定义各种配置属性。
Example
以下示例创建了一个新数据库并在其中创建了一个对象存储 −
<!DOCTYPE html>
<html lang="en">
<head>
<title>Creating Object Store</title>
</head>
<body>
<script>
var request = indexedDB.open("myDatabase", 2);
request.onupgradeneeded = event => {
var db = event.target.result;
var objectStore = db.createObjectStore("customers");
document.write("Object store Created Successfully...");
};
</script>
</body>
</html>
Defining primary keys
类似于 RDBMS,我们需要主键来唯一地定义对象存储中的某些数据。可以使用密钥路径或密钥生成器以 2 种方式来实现这一点。
Keypath and Key generator
key path 是总是存在的属性,并且包含惟一的值。我们可以选择一个惟一的值,如电子邮件地址。
key generator 为添加到对象存储中的每个对象创建一个惟一的值。默认情况下,如果我们不提及密钥生成器则会进入该图像。例如,自动递增。
Syntax
以下是对象存储上创建密钥路径的语法。
var objectStore = db.createObjectStore("ObjectStoreName", { keyPath: "primary key, autoincrement/autoDecrement : true" });
Example
在下面给出的示例中,我们正在使用 JavaScript 创建到对象存储的密钥路径 −
<!DOCTYPE html>
<html lang="en">
<head>
<title>keypath</title>
</head>
<body>
<script>
var request = indexedDB.open("myDtabase", 2);
request.onupgradeneeded = event => {
var db = event.target.result;
var objectStore = db.createObjectStore("customers",{keyPath:"id", autoIncrement:true});
document.write("Object store Created Successfully...");
};
</script>
</body>
</html>
Verification
如果上述程序执行成功,当您展开 “myDatabase” 时,您可以看到新创建的对象存储,如果单击它,则可以看到为 “id” 创建了密钥路径。
创建新的对象存储时,它们会像上面一样在 IndexedDB 文件夹中提及。
你可以同时使用键路径和键生成器。如果数据总能是唯一的,我们可以使用一个 keypath,否则如果值更改,你可以使用一个键生成器,如果你想为每一个值更改值,但希望提供唯一地表示存储的值,我们可以两个都用。
Defining Indexes
索引是一种对象存储。它们用于从存储在指定属性中的引用对象检索数据。索引使用指定属性作为其键路径,而不是引用存储的主键。
要创建索引,你需要在 createIndex() 实例上调用 object store 方法。
Syntax
下面是 createIndex() 方法的语法 −
var myIDBIndex = objectStore.createIndex(indexName, keyPath);
var myIDBIndex = objectStore.createIndex(indexName, keyPath, Parameters);
其中,
-
indexName 是创建的索引的名称。
-
Keypath 是在创建对象存储时主定义
-
最后一个参数的值可以是 unique 或 multi-entry ,以防您 “pass unique: true” 。索引不会允许单个键重复值。如果你通过 “multi-entry: true” 。当 keyPath 解析为数组时,索引会为每个数组元素添加一个条目。如果为 false,它将添加包含数组的一个单一条目。
Example
以下 JavaScript 示例演示如何创建索引。
<!DOCTYPE html>
<html lang="en">
<head>
<title>OPENING A DATABASE</title>
</head>
<body>
<script>
const dbName = "myDB";
const studentdata = [
{name : "jason" , rollno: "160218737028" , branch : "IT"},
{name : "lokesh" , rollno: "160218735020" , branch : "CSE"},
{name : "tarun" , rollno: "160218733057" , branch : "EEE"},
{name : "pranith" , rollno: "160218737029" , branch : "IT"}
];
var request = indexedDB.open("myDB", 2);
request.onupgradeneeded = event => {
var db = event.target.result;
var objectStore = db.createObjectStore("student",{ keyPath :"rollno" });
objectStore.createIndex("name", "name", { unique: false });
objectStore.createIndex("branch", "branch", { unique: false });
objectStore.transaction.oncomplete = event => {
var objectStore = db.transaction("student", "readwrite").objectStore("student");
studentdata.forEach(function(student) {
objectStore.add(student);
});
};
};
</script>
</body>
</html>
Output
如果您去验证 IndexedDB 数据库 myDB 的内容并展开它,您将观察被创建的表如下 −
如果您点击名称和学生值,您将观察索引值如下 −
Name index
# |
Key(Key path:"name") |
Primary key (Key path:"rollno") |
Value |
0 |
"jason" |
"160218737028" |
{name: 'jason', rollno: '160218737028', branch:1. branch: "IT"2. name: "jason"3. rollno: "160218737028" |
1 |
"lokesh" |
"160218735020" |
{name: 'lokesh', rollno: '160218735020', branch: 'CSE'}1. branch: "CSE"2. name: "lokesh"3. rollno: "160218735020" |
2 |
"pranith" |
"160218737029" |
{name: 'pranith', rollno: '160218737029', branch: 'IT'}1. branch: "IT"2. name: "pranith"3. rollno: "160218737029" |
3 |
"tarun" |
"160218733057" |
{name: 'tarun', rollno: '160218733057', branch: 'EEE'}1. branch: "EEE"2. name: "tarun"3. rollno: "160218733057" |
Branch Index
# |
Key(Key path:"branch") |
Primary key (Key path:"rollno") |
Value |
0 |
"CSE" |
"160218735020" |
{name:'lokesh', rollno:'160218735020', branch: 'CSE'}1. branch: "CSE"2. name: "lokesh"3. rollno: "160218735020" |
1 |
"EEE" |
"160218733057" |
{name:'tarun', rollno: '160218733057', branch: 'EEE'}1. branch: "EEE"2. name: "tarun"3. rollno: "160218733057" |
2 |
"IT" |
"160218737028" |
{name:'jason', rollno: '160218737028', branch: 'IT'}1. 专业:\"IT\"2. 姓名:\"jason\"3. 学号:\"160218737028\" |
3 |
"IT" |
"160218737029" |
{name:'pranith', rollno: '160218737029', branch: 'IT'}1. 专业:\"IT\"2. 姓名:\"pranith\"3. 学号:\"160218737029\" |
Deleting Object Store
对象存储与数据库中的表类似,当不需要该表时,我们可以删除表。类似地,当不再使用对象存储时,您可以删除该对象存储。要删除对象存储,您需要调用 deleteObjectStore() 函数。
Syntax
以下是 deleteObjectStore() 函数的语法 −
db.deleteObjectStore("store_name");
其中,store_name是您需要删除的对象存储的名称。
Example
让我们看一个删除不再必需的对象存储的 JavaScript 示例 −
<!DOCTYPE html>
<html lang="en">
<head>
<title>OPENING A DATABASE</title>
</head>
<body>
<script>
const dbName = "Database";
var request = indexedDB.open("Database", 2);
request.onupgradeneeded = event => {
var db = event.target.result;
var objectStore = db.createObjectStore("student",{ keyPath :"rollno" } );
var objstore = db.createObjectStore("college",{autoIncrement : true});
db.deleteObjectStore("college");
};
</script>
</body>
</html>
IndexedDB - Creating Data
在创建数据之前,我们需要了解如何传输数据。IndexedDB 打开事务,其每项数据操作都在这些事务中执行。每项操作有四个步骤 −
-
Get database object
-
在数据库上打开事务
-
在事务上打开对象存储
-
在对象存储上操作
IndexedDB 中的操作 −
-
create
-
read
-
update
-
delete
首先,为了在数据库中执行任何操作,我们需要打开一个事务。打开事务后,我们需要获取所需的存储对象。这些对象存储仅根据创建事务时指定的存储要求提供。然后,稍后可以添加任何所需的数据。
函数用于执行给定操作(如果有)。例如,我们使用 add() 函数向数据库中添加数据或添加新条目。
Example
在以下示例中,我们使用 JavaScript 中的 add() 方法向对象存储中插入数据 −
<!DOCTYPE html>
<html lang="en">
<head>
<title>creating data</title>
</head>
<body>
<script>
const dbName = "Database";
var request = indexedDB.open("Database", 2);
request.onupgradeneeded = event => {
var db = event.target.result;
var objectStore = db.createObjectStore("student",{ keyPath :"rollno" } );
};
request.onsuccess = event => {
document.write("Database opened successfully");
var db = event.target.result;
var transaction = db.transaction("student", "readwrite");
var objectStore = transaction.objectStore("student");
objectStore.add({ rollno: 160218737028, name: "jason", branch: "IT" });
objectStore.add({ rollno: 160218733028, name: "tarun", branch: "EEE" });
objectStore.add({ rollno: 160218732028, name: "lokesh", branch: "CSE" });
objectStore.add({ rollno: 160218737025, name: "abdul", branch: "IT" });
objectStore.add({ rollno: 160218736055, name: "palli", branch: "MECH" });
}
transaction.oncomplete = function () {
db.close();
};
</script>
</body>
</html>
Output
0 160218732028
{rollno: 160218732028, name: 'lokesh', branch: 'CSE'}
1 160218733028
{rollno: 160218733028, name: 'tarun', branch: 'EEE'}
2 160218736055
{rollno: 160218736055, name: 'palli', branch: 'CSE'}
3 160218737025
{rollno: 160218737025, name: 'abdul', branch: 'IT'}
4 160218737028
{rollno: 160218737028, name: 'jason', branch: 'IT'}
IndexedDB - Reading Data
我们将数据输入数据库,并且我们需要调用数据以查看更改以及用于其他各种目的。
我们必须对对象存储调用 get() 方法才能读取此数据。get 方法接收要从存储中检索的对象的主键。
Example
以下示例是如何实现请求 objectstore 以获取数据的 −
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<script>
const request = indexedDB.open("botdatabase",1);
request.onupgradeneeded = function(){
const db = request.result;
const store = db.createObjectStore("bots",{ keyPath: "id"});
}
request.onsuccess = function(){
document.write("database opened successfully");
const db = request.result;
const transaction=db.transaction("bots","readwrite");
const store = transaction.objectStore("bots");
store.add({id: 1, name: "jason",branch: "IT"});
store.add({id: 2, name: "praneeth",branch: "CSE"});
store.add({id: 3, name: "palli",branch: "EEE"});
store.add({id: 4, name: "abdul",branch: "IT"});
const idquery = store.get(4);
idquery.onsuccess = function(){
document.write("idquery",idquery.result);
}
transaction.oncomplete = function(){
db.close;
}
}
</script>
</body>
</html>
IndexedDB - Updating Data
创建数据后,下一步是执行各种操作;因此,我们需要定期更新数据。在数据库中输入数据不正确的情况下,还需要更新数据。在这里,我们必须指定一个读写事务,因为我们希望写入数据库,而不仅仅是从数据库中读取。
如果我们要修改或进行数据库中已存在的条目,我们将使用 put() 函数。
Example
让我们看下面的脚本,以了解如何使用 put() 函数更新或修改 objectstore 中的数据 -
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<script>
const request = indexedDB.open("botdatabase",1);
request.onupgradeneeded = function(){
const db = request.result;
const store = db.createObjectStore("bots",{ keyPath: "id"});
}
request.onsuccess = function(){
document.write("database opened successfully");
const db = request.result;
const transaction=db.transaction("bots","readwrite");
const store = transaction.objectStore("bots");
store.add({id: 1, name: "jason",branch: "IT"});
store.add({id: 2, name: "praneeth",branch: "CSE"});
store.add({id: 3, name: "palli",branch: "EEE"});
store.add({id: 4, name: "abdul",branch: "IT"});
store.put({id: 4, name: "deevana",branch: "CSE"});
const idquery = store.get(4);
idquery.onsuccess = function(){
document.write("idquery",idquery.result);
}
transaction.oncomplete = function(){
db.close;
}
}
</script>
</body>
</html>
IndexedDB - Deleting Data
在许多情况下,我们需要从数据库中删除数据,无论是出于存储目的,还是只是为了删除不想保留的数据以释放空间。如果我们希望从数据库中删除此不必要的数据,则可以使用 .delete() 函数。
Example
我们来看一个用于删除数据的示例脚本 −
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<script>
const request = indexedDB.open("botdatabase",1);
request.onupgradeneeded = function(){
const db = request.result;
const store = db.createObjectStore("bots",{ keyPath: "id"});
}
request.onsuccess = function(){
document.write("database opened successfully");
const db = request.result;
const transaction=db.transaction("bots","readwrite");
const store = transaction.objectStore("bots");
store.add({id: 1, name: "jason",branch: "IT"});
store.add({id: 2, name: "praneeth",branch: "CSE"});
store.add({id: 3, name: "palli",branch: "EEE"});
store.add({id: 4, name: "abdul",branch: "IT"});
store.put({id: 4, name: "deevana",branch: "CSE
const deletename = store.delete(1);
deletename.onsuccess = function(){
document.write("id : 1 has been deleted");
}
transaction.oncomplete = function(){
db.close;
}
}
</script>
</body>
</html>
IndexedDB - Using getAll() Function
在前几部分中,我们一次只从存储中检索对象。现在,我们可以检索所有数据或对象存储的子集。获取 all 方法使用 getAll() 函数返回对象存储中的所有对象
Syntax
ObjectStore.getAll(optionalConstraint);
我们可以直接调用 getAll() 以返回存储在对象库中的所有对象,或者我们可以指定一个可选约束,例如从汽车数据库中获得红色轿车
Example
在以下示例脚本中,我们正在调用 getAll() 方法以一次性返回存储在对象库中的所有对象
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<script>
const request = indexedDB.open("botdatabase",1);
request.onupgradeneeded = function(){
const db = request.result;
const store = db.createObjectStore("bots",{ keyPath: "id"});
store.createIndex("branch_db",["branch"],{unique: false});
}
request.onsuccess = function(){
document.write("database opened successfully");
const db = request.result;
const transaction=db.transaction("bots","readwrite");
const store = transaction.objectStore("bots");
const branchIndex = store.index("branch_db");
store.add({id: 1, name: "jason",branch: "IT"});
store.add({id: 2, name: "praneeth",branch: "CSE"});
store.add({id: 3, name: "palli",branch: "EEE"});
store.add({id: 4, name: "abdul",branch: "IT"});
store.put({id: 4, name: "deevana",branch: "CSE"});
const query = branchIndex.getAll(["IT"]);
query.onsuccess = function(){
document.write("query",query.result);
}
transaction.oncomplete = function(){
db.close;
}
}
</script>
</body>
</html>
IndexedDB - Indexes
索引是一种用于从由指定属性存储的参考对象检索数据的对象存储。即使索引在参考对象存储中并且包含相同数据,但它不使用参考存储的主键,而是使用指定的属性作为其关键路径。
索引用于定义针对数据唯一约束,它们在创建对象存储时创建。要创建索引,请在对象存储实例上调用 createIndex 方法 -
Syntax
var myIDBIndex = objectStore.createIndex(indexName, keyPath);
var myIDBIndex = objectStore.createIndex(indexName, keyPath, objectParameters);
此方法创建一个索引对象并返回它。该方法创建包含以下参数的索引 -
-
Index name - 索引的名称。
-
Keypath - 我们在此处注明主键。
-
Object Parameters - 有两个对象参数。
-
Unique - 无法添加重复值。
-
Multi entry - 如果为 true,则当 keyPath 解析为 Array 时,索引会为每个数组元素在索引中添加一个条目。如果为 false,它将添加包含 Array 的单个条目。
Example
以下示例显示了在对象存储中实现索引 -
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<script>
const request = indexedDB.open("botdatabase",1);
request.onupgradeneeded = function(){
const db = request.result;
const store = db.createObjectStore("bots",{ keyPath: "id"});
store.createIndex("branch_db",["branch"],{unique: false});
}
request.onsuccess = function(){
document.write("database opened successfully");
const db = request.result;
const transaction=db.transaction("bots","readwrite");
const store = transaction.objectStore("bots");
const branchIndex = store.index("branch_db");
store.add({id: 1, name: "jason",branch: "IT"});
store.add({id: 2, name: "praneeth",branch: "CSE"});
store.add({id: 3, name: "palli",branch: "EEE"});
store.add({id: 4, name: "abdul",branch: "IT"});
store.put({id: 4, name: "deevana",branch: "CSE"});
transaction.oncomplete = function(){
db.close;
}
}
</script>
</body>
</html>
Output
branchIndex:
1
['CSE']
0: "CSE"
length: 1
4
{id: 4, name: 'deevana', branch: 'CSE'}
branch: "CSE"
id: 4
name: "deevana"
2
['EEE']
0: "EEE"
length: 1
3
{id: 3, name: 'palli', branch: 'EEE'}
branch: "EEE"
id: 3
name: "palli"
3
['IT']
0: "IT"
length: 1
1
{id: 1, name: 'jason', branch: 'IT'}
branch: "IT"
id: 1
name: "jason"
IndexedDB - Ranges
如果我们不想一次获得全部数据,则使用范围。如果我们只想获得特定范围内的的数据,则使用范围。我们使用 IDBKeyRange 对象来定义范围。此对象具有 4 个方法,分别是 −
-
upperBound()
-
lowerBound()
-
bound()
-
only()
Syntax
IDBKeyRange.lowerBound(indexKey);
IDBKeyRange.upperBound(indexKey);
IDBKeyRange.bound(lowerIndexKey, upperIndexKey);
下表列出了各种范围代码 −
S.No. |
Range Codes & Description |
1 |
All keys ≥ a DBKeyRange.lowerBound(a) |
2 |
All keys > a IDBKeyRange.lowerBound(a, true) |
3 |
All keys ≤ b IDBKeyRange.upperBound(b) |
4 |
All keys < b IDBKeyRange.upperBound(b, true) |
5 |
All keys ≥ a && ≤ b IDBKeyRange.bound(a, b) |
6 |
All keys > a &&< b IDBKeyRange.bound(a, b, true, true) |
7 |
All keys > a && ≤ b IDBKeyRange.bound(a, b, true, false) |
8 |
All keys ≥ a && < b IDBKeyRange.bound(a, b, false, true) |
9 |
The key = c IDBKeyRange.only(c) |
我们通常使用索引来使用范围,并且在句法中,索引键表示索引键路径值。
Examples
使用 get() 和 getAll() 方法来检索范围代码的各种示例如下所示:
class.get(‘student’)
class.getAll(IDBKeyRange.bound(‘science’,’math’)
class.getAll(IDBKeyRange.upperbound(‘science’,true)
class.getAll()
class.getAllKeys(IDBKeyRange.lowerbound(‘student’,true))
HTML Example
考虑以下 HTML 示例以获取范围代码:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<script>
const request = indexedDB.open("botdatabase",1);
request.onupgradeneeded = function(){
const db = request.result;
const store = db.createObjectStore("bots",{ keyPath: "id"});
store.createIndex("branch_db",["branch"],{unique: false});
}
request.onsuccess = function(){
document.write("database opened successfully");
const db = request.result;
const transaction=db.transaction("bots","readwrite");
const store = transaction.objectStore("bots");
const branchIndex = store.index("branch_db");
store.add({id: 1, name: "jason",branch: "IT"});
store.add({id: 2, name: "praneeth",branch: "CSE"});
store.add({id: 3, name: "palli",branch: "EEE"});
store.add({id: 4, name: "abdul",branch: "IT"});
store.put({id: 4, name: "deevana",branch: "CSE"});
const upperquery =store.getAll(IDBKeyRange.upperBound('2', true));
upperquery.onsuccess = function(){
document.write("upperquery",upperquery.result);
}
transaction.oncomplete = function(){
db.close;
}
}
</script>
</body>
</html>
Output
database opened successfully
upperquery (4) [{...}, {...}, {...}, {...}]
arg1: (4) [{...}, {...}, {...}, {...}]
0: {id: 1, name: 'jason', branch: 'IT'}
1: {id: 2, name: 'praneeth', branch: 'CSE'}
2: {id: 3, name: 'palli', branch: 'EEE'}
3: {id: 4, name: 'deevana', branch: 'CSE'}
length: 4
[[Prototype]]: Array(0)
[[Prototype]]: Object
IndexedDB - Transactions
事务是一组操作,这些操作要么全部成功,要么全部失败。例如,如果我们通过 UPI 向商家付款,但交易被拒绝,那该笔钱必须退回发送者的帐户。事务维持这种完整性。
以下是如何开启事务的语法:
db.transaction(store[, type]);
此处的存储是我们要在其中执行事务的对象存储。事务的类型有两种:
-
read-only - 只能读取,它在默认情况下已提供。
-
read-write - 我们可以只读取和写入数据,但我们不能创建、删除或从对象存储中对其进行更改。
Transaction life cycle
事务是对象存储之间执行任何操作的连接。每个事务都有一个状态,该状态可以是:
-
active - 当第一次创建事务时。或当一个请求与事务关联时。当它处于该状态时,可以针对事务进行新请求。
-
inactive - 在事件创建后返回控制后,事务处于该状态。当它处于该状态时,无法针对事务提出任何请求。
-
committing - 当与某个事务关联的所有请求都完成后,它将尝试提交。在提交状态期间,无法进行任何新请求。
-
finished - 在一个事务提交或中止之后,它处于完成状态。在完成状态期间,无法进行任何新请求。
The lifetime of a transaction
会形成一个具有范围和模式的事务。当事务生成后,其状态最初是激活的。
-
为了开始事务,该实现必须排队一个任务。
-
当与事务关联的每个请求被处理后,会触发一个成功或错误事件。在发送事件时,事务状态被设置为激活的,从而允许针对事务进行后续请求。事件分发完成后,事务的状态被设置为非激活的。
-
事务可以在完成之前任何时候取消,即使它当前未处于活动状态或尚未开始。
-
当针对数据库进行的所有请求都成功时,该实现必须尝试提交事务。
-
当提交或撤销事务时,其状态将设置为结束。
Transaction scheduling
当事务可以启动时,有一些限制。
-
当没有读或写事务时:a. 在事务 tx 之前建立的 b. 与 tx 有重叠范围的 c. 不处于最终状态的,只读事务 tx 才能开始。
-
当没有其他事务时,读/写事务 tx 才能开始 - 在 tx 之前形成的,与 tx 有重叠范围的,或不处于完成状态的。
Upgrade transactions
模式为 " versionchange " 的事务是升级事务。
对象存储和数据库中的索引可以使用升级操作进行创建、重命名和删除。
如果给出的版本大于当前版本,则在打开与数据库的连接后完成运行升级事务的步骤时自动生成升级事务。在 upgradeneeded 事件处理程序中,此事务将处于活动状态。
Committing a transaction
必须完成以下步骤才能提交事务 -
-
首先将事务状态设置为提交。
-
等到列表中的所有事务请求都已处理。
-
如果发生错误,请中止事务。
-
如果事务是升级事务,则将数据库升级事务的事务连接设置为 NULL。
-
将事务状态更改为完成。
-
触发事务的整个事件
-
如果事务是升级事务,则将请求的事务设置为 null 并在事务中进行关联的请求。
Syntax
transaction.commit()
尝试提交事务。将允许所有挂起请求完成,但不会接受任何新请求。
如果挂起的请求失败,则事务将中止。成功请求的成功事件仍将触发,但在事件处理程序中抛出异常不会中止事务,调用 preventDefault() 不会阻止事务中止。
Event Handlers
各种事件处理程序属性如下所示
attribute EventHandler onabort;
attribute EventHandler oncomplete;
attribute EventHandler onerror;
Transactions Example
下面给出了一个简单的 JavaScript 程序来演示事务的使用 -
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<script>
const request = indexedDB.open("botdatabase",1);
request.onupgradeneeded = function(){
const db = request.result;
const store = db.createObjectStore("bots",{ keyPath: "id"});
}
request.onsuccess = function(){
document.write("database opened successfully");
const db = request.result;
const transaction=db.transaction("bots","readwrite");
const store = transaction.objectStore("bots");
store.add({id: 1, name: "jason",branch: "IT"});
store.add({id: 2, name: "praneeth",branch: "CSE"});
store.add({id: 3, name: "palli",branch: "EEE"});
store.add({id: 4, name: "abdul",branch: "IT"});
store.put({id: 4, name: "deevana",branch: "CSE"});
transaction.oncomplete = function(){
document.write("transaction complete");
db.close;
};
}
</script>
</body>
</html>
Output
database opened successfully
transaction complete
在这里创建事务,只有在创建事务时才能将数据添加到对象存储中,最终在事务完成后,我们关闭数据库。
Example
以下示例演示了一个事务属性 oncomplete 的用法 -
function student(db, names) {
let transaction = db.transaction(['names'], 'readwrite');
let store = transaction.objectStore('names');
for (let i = 0; i < messages.length; i++) {
store.add({text: names[i]});
}
transaction.oncomplete = function()
{document.write('transaction complete')};
}
IndexedDB - Error Handling
我们编写的并非所有请求都会返回输出。这可能是由于 -
-
编写代码时可能出错。
-
如果存储限制已超。
-
如果事务失败等。
在失败的请求中,事务被取消,并且所有更改都被恢复。但有时我们希望在不恢复所有更改的情况下处理失败,为此可使用 request.onerror 处理程序。它可以通过调用 event.preventDefault() 来防止事务中止。
Example
以下给出了在 IndexedDB 中显示错误处理的一个示例:
<!DOCTYPE html>
<html lang="en">
<head>
<title>IndexedDB</title>
</head>
<body>
<script>
const request = indexedDB.open("DATABASE", 1);
request.onsuccess = function (){
document.write("database creation success")
}
request.onerror = function(event){
document.write("Database not created " + event.target.errorCode);
}
</script>
</body>
</html>
Output
Database not created undefined
我们可以通过为此使用 db.onerror 处理程序来捕获错误。
db.onerror = function(event) {
let request = event.target;
document.write("Error is found", request.error);
};
当具有相同 id 的对象已存在时,会发生约束错误。但有时,如果一个错误得到完全处理,并且我们不想报告该错误,则可以通过在 request.onerror 中使用 event.stopPropagation() 来阻止冒泡。
request.onerror = function(event) {
if (request.error.name == "ConstraintError") {
document.write("id already exists");
event.preventDefault();
event.stopPropagation();
}
}
IndexedDB - Searching
我们遇到许多情况,需要在对象存储中搜索值。对象存储在内部进行排序。可以通过以下方式完成:
-
根据键值或键范围进行搜索。
-
根据另一个对象字段进行搜索。
Searching by Key
我们可以通过对一个可接受的键范围使用 IDBKeyRange 对象,来搜索精确的键值或键值范围。IDBKeyRange 对象具有以下调用:
-
IDBKeyRange.lowerBound(lower, [open]) for >=lower
-
IDBKeyRange.upperBound(upper, [open]) for >=upper
-
IDBKeyRange.bound(lower, upper, [lowerOpen] , [upperOpen]) 在 lower 和 upper 之间
-
IDBKeyRange.only(key) 如果范围只包含一个键。
为了执行实际搜索,我们在对象存储上使用查询参数。用于执行这些操作的不同类型的函数是:
-
store.get(query) - 根据键或范围搜索存储中的第一个值
-
store.getAll([query],[count]) - 根据提到的计数限制搜索存储中的所有值。
-
store.getKey(query) - 搜索第一个满足查询的键。
-
store.getAllKeys([query],[count]) - 搜索所有满足查询的键,直到完成计数限制。
-
store.count([query]) - 获取满足查询的键的总数。
Searching by a field or index
为了根据其他对象字段进行搜索,我们需要使用索引。索引存储具有所需值的对象的键列表。索引在内部也像对象存储一样进行排序。
Syntax
objectStore.createIndex(name, keyPath, [options]);
name - 索引名称
keyPath - 将在对象字段的路径上进行搜索
options - 选项分为 2 类
-
unique - 具有唯一值的对象存储中的对象将位于关键路径中,并且无法复制它们。
-
multi−entry - 如果关键路径上的值为数组,则默认情况下,该索引将把整个数组视为键,但如果我们使用多条目,则该数组成员会变为索引键。
Example
如果我们想要根据价格搜索电话,则示例程序如下所示:
openRequest.onupgradeneeded = function() {
let books = db.createObjectStore('phone', {keyPath: 'id'});
let index = books.createIndex('pricephone', 'price');
};
要创建索引,我们需要使用升级项。
-
该索引将跟踪价格字段。
-
如果价格不是唯一的,我们无法设置 unique 选项。
-
如果价格不是数组,则 multiEntry 不可应用。
Example
在以下示例中,我们创建一个事务,并使用 getAll() 函数检索所有对象。检索这些对象后,我们搜索该事务中的对象值。如果找到,则返回该对象;如果没有,则返回 false。
let transaction = db.transaction("phones");
let books = transaction.objectStore("phones");
let priceIndex = books.index("price_index");
let request = priceIndex.getAll(7);
request.onsuccess = function() {
if (request.result !== undefined) {
document.write("Phones", request.result);
} else {
document.write("There are no such phones");
}
};
HTML Example
搜索对象存储中值的 HTML 脚本实现如下:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<script>
const request = indexedDB.open("botdatabase",1);
request.onupgradeneeded = function(){
const db = request.result;
const store = db.createObjectStore("bots",{ keyPath: "id"});
store.createIndex("branch_db",["branch"],{unique: false});
}
request.onsuccess = function(){
document.write("database opened successfully");
const db = request.result;
const transaction=db.transaction("bots","readwrite");
const store = transaction.objectStore("bots");
const branchIndex = store.index("branch_db");
store.add({id: 1, name: "jason",branch: "IT"});
store.add({id: 2, name: "praneeth",branch: "CSE"});
store.add({id: 3, name: "palli",branch: "EEE"});
store.add({id: 4, name: "abdul",branch: "IT"});
store.put({id: 4, name: "deevana",branch: "CSE"});
const req = branchIndex.getAll(["CSE"]);
req.onsuccess = function(){
if(req.result!==undefined){
document.write("bots",req.result);
} else{
document.write("There are no such bots");
}
};
transaction.oncomplete = function(){
db.close;
}
}
</script>
</body>
</html>
IndexedDB - Cursors
在检索数据时,当我们知道想要检索哪个键时,我们使用了 get() 函数,但如果我们想要逐个浏览对象存储的所有值,我们可以使用游标。
首先我们使用 open cursor 函数,然后我们可以向其中添加我们的参数。我们可以在 openCursor() 函数中插入的参数如下:
-
利用键范围限制对象范围
-
我们希望迭代的方向
以下是游标的语法
Syntax
ObjectStore.openCursor(optionalKeyRange, optionalDirection);
对于对象存储,我们使用 openCursor()
-
optionalKeyRange - 我们可以限制我们需要检索的对象范围。
-
optionalDirection - 我们可以指定我们希望迭代的方向。
Example 1
在此示例中,我们了解如何使用 JavaScript 打开游标函数:
var objectStore = db.transaction("student").objectStore("student”);
objectStore.openCursor().onsuccess = event => {
var cursor = event.target.result;
if (cursor) {
document.write("Name" + cursor.key + cursor.value.name);
cursor.continue();
} else {
document.write("entries closed");
}
};
Example 2
当我们想从对象存储中检索所有对象并将其放置到数组中时。
var student = [];
objectStore.openCursor().onsuccess = event => {
var cursor = event.target.result;
if (cursor) {
student.push(cursor.value);
cursor.continue();
} else {
document.write(student);
}
};
Example 3
下面是另一个使用 JavaScript 中的 openCursor() 函数的示例 −
var singleKeyRange = IDBKeyRange.only("Jason");
var lowerBoundKeyRange = IDBKeyRange.lowerBound("Praneeth");
var lowerBoundOpenKeyRange = IDBKeyRange.lowerBound("jason", true);
var upperBoundOpenKeyRange = IDBKeyRange.upperBound("praneeth", true);
var boundKeyRange = IDBKeyRange.bound("jason", "praneeth", false, true);
index.openCursor(boundKeyRange).onsuccess = event => {
var cursor = event.target.result;
if (cursor) {
cursor.continue();
}
};
或者如果我们想给出方向 −
objectStore.openCursor(boundKeyRange, "prev").onsuccess = event => {
var cursor = event.target.result;
if (cursor) {
cursor.continue();
}
};
HTML Example
按照如下内容实现游标函数使用情况的 HTML 脚本 −
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<script>
const request = indexedDB.open("botdatabase",1);
request.onupgradeneeded = function(){
const db = request.result;
const store = db.createObjectStore("bots",{ keyPath: "id"});
store.createIndex("branch_db",["branch"],{unique: false});
}
request.onsuccess = function(){
document.write("database opened successfully");
const db = request.result;
const transaction=db.transaction("bots","readwrite");
const store = transaction.objectStore("bots");
const branchIndex = store.index("branch_db");
store.add({id: 1, name: "jason",branch: "IT"});
store.add({id: 2, name: "praneeth",branch: "CSE"});
store.add({id: 3, name: "palli",branch: "EEE"});
store.add({id: 4, name: "abdul",branch: "IT"});
store.put({id: 4, name: "deevana",branch: "CSE"});
const req = store.openCursor();
req.onsuccess = function(){
const cursor = req.result;
if(cursor){
const key = cursor.key;
const value = cursor.value;
document.write(key,value);
cursor.continue();
} else {
document.write("bots completed");
}
}
transaction.oncomplete = function(){
db.close;
}
}
</script>
</body>
</html>
IndexedDB - Promise Wrapper
Promises ,就像回调函数一样,是一种在不对 javascript 的运行时线程停止的情况下告知你的代码完成异步操作时要执行什么操作的技术。
与在异步函数完成后提供回调函数来运行的方式不同,可以使用 promise 代替。
Promise 库是 Jake Archibald 创建的,它使用 promise 而不是事件。
使用起来比传统的 IndexedDB 更加容易。它简化了 API,同时仍然保留了 API 的结构。
这里我们仅展示了为什么我们可以使用 Promise 库的原因,要了解关于它的更多信息,您可以访问以下网站 −
它有一些增强功能 −
-
IDBDatabase
-
IDBTransaction
-
IDBCursor
IDBDatabase
从对象存储获取或设置的快捷方式
const value = await db.get(storeName, key);
await db.put(storeName, value, key);
从索引获取的快捷方式
const value = await db.getFromIndex(storeName, indexName, key);