作者选择了 /dev/color以作为 Write for Donations计划的一部分获得捐款。
介绍
SQLite是一个流行的开源SQL数据库引擎,用于存储数据,它是无服务器的,这意味着它不需要一个服务器运行;相反,它读取和写入数据到位于计算机磁盘上的文件。
要使用 SQLite 与 Node.js,您需要一个连接到 SQLite 数据库的数据库客户端,并将 SQL 陈述从您的应用程序发送到数据库进行执行。
在本教程中,您将使用node-sqlite3
创建与 SQLite 数据库的连接。接下来,您将创建一个 Node.js 应用程序,创建表并将数据插入数据库。
前提条件
要遵循本教程,您将需要:
如果你正在使用Ubuntu 22.04,安装最新版本的Node.js,通过遵循我们的教程(How To Install Node.js on Ubuntu 22.04)(https://andsky.com/tech/tutorials/how-to-install-node-js-on-ubuntu-22-04)的选项3。 对于其他系统,请参阅我们的教程系列(How to Install Node.js and Create a Local Development Environment)(https://www.digitalocean.com/community/tutorial_series/how-to-install-node-js-and-create-a-local-development-environment)。
- SQLite3安装在你的开发环境。 遵循我们的教程(How To Install and Use SQLite on Ubuntu 20.04)(https://andsky.com/tech/tutorials/how-to-install-and-use-sqlite-on-ubuntu-20-04)的步骤1)。
- 关于如何创建表和写SQL查询以获取和修改表中的数据的基本知识。 遵循我们的教程(How To Install and Use SQL on Ubuntu 20.04)(LINK2)的步骤2到6。
- 熟悉如何
步骤 1 – 设置项目目录
在此步骤中,您将创建项目目录并下载node-sqlite3
作为依赖。
首先,使用mkdir
命令创建一个目录,它被称为sqlite_demo
,但您可以用您所选择的名称替换:
1mkdir sqlite_demo
接下来,使用cd
命令更改新创建的目录:
1cd sqlite_demo
使用npm
命令将项目目录初始化为 npm 包:
1npm init -y
该命令会创建一个package.json
文件,其中包含您项目的重要元数据。
运行命令后,下列输出将显示在您的屏幕上:
1[secondary_label Output]
2Wrote to /home/sammy/sqlite_demo/package.json:
3
4{
5 "name": "sqlite_demo",
6 "version": "1.0.0",
7 "description": "",
8 "main": "index.js",
9 "scripts": {
10 "test": "echo \"Error: no test specified\" && exit 1"
11 },
12 "keywords": [],
13 "author": "",
14 "license": "ISC"
15}
输出表明已创建了 package.json
文件,其中包含记录您项目的重要元数据的属性。
名称
:您的项目名称.版本
:您的项目版本.main
:您的项目的起点。
您可以将默认选项留在原样,但可以随意修改属性值以满足您的偏好。 有关属性的更多信息,请参阅 npm 的 package.json 文档。
接下來,安裝「node-sqlite3」包與「npm install」:
1npm install sqlite3
安装包后,输出将显示如下:
1[secondary_label Output]
2added 104 packages, and audited 105 packages in 9s
3
45 packages are looking for funding
5 run `npm fund` for details
6
7found 0 vulnerabilities
现在您已经安装了node-sqlite3
,您将在下一节中使用它来连接到 SQLite 数据库。
步骤 2 — 连接到 SQLite 数据库
在此步骤中,您将使用node-sqlite3
将您的 Node.js 程序连接到您将创建的 SQLite 数据库中,其中包含不同的鲨鱼及其属性。 为了建立数据库连接,node-sqlite3
包提供了一个数据库
类别。 在实例化时,该类会在您的计算机磁盘上创建一个 SQLite 数据库文件并连接到它。 一旦建立了连接,您将为您的应用程序创建一个表,在以后的部分中,您将使用它来插入、检索或更新数据。
使用nano
或您最喜欢的文本编辑器,创建并打开db.js
文件:
1nano db.js
在您的「db.js」文件中,添加以下代码以建立与 SQLite 数据库的连接:
1[label sqlite_demo/db.js]
2const sqlite3 = require("sqlite3").verbose();
3const filepath = "./fish.db";
4
5function createDbConnection() {
6 const db = new sqlite3.Database(filepath, (error) => {
7 if (error) {
8 return console.error(error.message);
9 }
10 });
11 console.log("Connection with SQLite has been established");
12 return db;
13}
在第一行中,你将node-sqlite3
模块导入你的程序文件. 在第二行中,你将变量filepath
设置为你想要 SQLite 数据库居住的路径和数据库文件的名称,在这种情况下是fish.db
。
在下一行中,您定义了与 SQLite 数据库建立连接的 createDbConnection()
函数. 在该函数中,您将 sqlite3.Database()
类与 new
关键字进行实例化。
第一个参数,filepath,接受 SQLite 数据库的名称和路径,即此处的 ./fish.db。第二个参数是在创建数据库并建立连接到数据库后运行的回调。回调采用一个
error参数,如果在尝试建立数据库连接时出现错误时设置为
error` 对象。
现在,当您使用sqlite3.Database()
类创建实例时,它会在项目目录中创建一个SQLite数据库文件,并返回存储在db
变量中的数据库对象。
最后,您调用「console.log()」来登录成功消息,并在「db」变量中返回数据库对象。
接下来,添加突出的代码来创建创建表的函数:
1[label sqlite_demo/db.js]
2...
3function createDbConnection() {
4 ...
5}
6
7function createTable(db) {
8 db.exec(`
9 CREATE TABLE sharks
10 (
11 ID INTEGER PRIMARY KEY AUTOINCREMENT,
12 name VARCHAR(50) NOT NULL,
13 color VARCHAR(50) NOT NULL,
14 weight INTEGER NOT NULL
15 );
16`);
17}
createTable()
函数在 SQLite 数据库中创建一个表格. 它将数据库对象db
作为参数。 在createTable()
函数中,您会调用数据库对象的exec()
方法,该方法将数据库发送给定的 SQL 陈述执行。
将CREATE TABLE sharks...
SQL 语句转移到exec()
方法将创建一个包含以下字段的表sharks
:
「ID」:存储「INTEGER」数据类型的值。「PRIMARY KEY」限制将列指定为主要密钥,而「AUTOINCREMENT」命令SQLite自动增加表中的每个行的「ID」列值。
- 'name':使用最多50个字符的「VARCHAR」数据类型详细说明鲨鱼的名称。「NOT NULL」限制确保该领域不能存储 NULL值。
- 'color':代表鲨鱼的颜色,使用「VARCHAR'数据类型最多50个字符。
在相同的 db.js
文件中,添加突出的代码来调用 createTable()
函数:
1[label sqlite_demo/db.js]
2function createDbConnection() {
3 const db = new sqlite3.Database(filepath, (error) => {
4 if (error) {
5 return console.error(error.message);
6 }
7 createTable(db);
8 });
9 console.log("Connection with SQLite has been established");
10 return db;
11}
12
13function createTable(db) {
14 ...
15}
当回调运行时,您将以db
数据库对象为参数,调用createTable()
函数。
接下来,添加以下行来调用createDbConnection()
函数:
1...
2function createDbConnection() {
3 ...
4}
5
6function createTable(db) {
7 ...
8}
9
10module.exports = createDbConnection();
在上面的代码中,您将调用createDbConnection()
函数,该函数将建立连接到数据库并返回数据库对象,然后使用module.exports
导出数据库对象,以便您可以在其他文件中引用它。
您的文件现在将包含以下内容:
1[label sqlite_demo/db.js]
2const sqlite3 = require("sqlite3").verbose();
3const filepath = "./fish.db";
4
5function createDbConnection() {
6 const db = new sqlite3.Database(filepath, (error) => {
7 if (error) {
8 return console.error(error.message);
9 }
10 createTable(db);
11 });
12 console.log("Connection with SQLite has been established");
13 return db;
14}
15
16function createTable(db) {
17 db.exec(`
18 CREATE TABLE sharks
19 (
20 ID INTEGER PRIMARY KEY AUTOINCREMENT,
21 name VARCHAR(50) NOT NULL,
22 color VARCHAR(50) NOT NULL,
23 weight INTEGER NOT NULL
24 );
25`);
26}
27
28module.exports = createDbConnection();
如果使用nano
,请按CTRL+X
来退出,按y
来保存所做的更改,然后按ENTER
来确认文件名。
使用node
命令运行db.js
文件:
1node db.js
输出将显示数据库连接已成功建立:
1[secondary_label Output]
2Connection with SQLite has been established
接下来,检查是否使用ls
命令创建了fish.db
数据库文件:
1ls
1[secondary_label Output]
2db.js fish.db node_modules package-lock.json package.json
fish.db
数据库文件在输出中显示,数据库已成功创建。
现在,每次运行db.js
文件时,它都会调用createTable()
函数来创建数据库中的表格。尝试创建一个已经存在的表格会引发SQLite的错误。
1node db.js
这一次,您将收到以下输出中显示的错误:
1[secondary_label Output]
2Connection with SQLite has been established
3undefined:0
4
5[Error: SQLITE_ERROR: table sharks already exists
6Emitted 'error' event on Database instance at:
7] {
8 errno: 1,
9 code: 'SQLITE_ERROR'
10}
11
12Node.js v17.6.0
错误消息表示鲨鱼
表已经存在,这是因为当您首次运行节点
命令时,创建了鱼
数据库以及鲨鱼
表。
此错误也会随时触发,您想要使用数据库对象方法来操纵其他文件中的数据库. 例如,在下一步,您将创建一个将数据插入数据库的文件. 要使用数据库对象,您将导入db.js
文件,并调用相关方法将数据插入数据库。
要解决此问题,您将使用fs
模块的existsSync()
方法检查项目目录中的fish.db
数据库文件是否存在.如果数据库文件存在,您将建立与数据库的连接,而不会调用createTable()
函数。
要做到这一点,请在编辑器中再次打开db.js
:
1nano db.js
在你的「db.js」文件中,添加突出的代码来检查数据库文件的存在:
1[label sqlite_demo/db.js]
2const fs = require("fs");
3const sqlite3 = require("sqlite3").verbose();
4const filepath = "./fish.db";
5
6function createDbConnection() {
7 if (fs.existsSync(filepath)) {
8 return new sqlite3.Database(filepath);
9 } else {
10 const db = new sqlite3.Database(filepath, (error) => {
11 if (error) {
12 return console.error(error.message);
13 }
14 createTable(db);
15 });
16 console.log("Connection with SQLite has been established");
17 return db;
18 }
19}
首先,您导入了用于与文件系统交互的fs
模块,其次,在添加的if
语句中,您调用了fs.existSync()
方法,以检查该参数中的文件是否存在,这里是数据库文件./fish.db
。如果该文件存在,则您通过数据库文件路径调用sqlite3.Database()
并省略调用。但是,如果该文件不存在,则您创建数据库实例,并在调用函数中调用createTable()
函数来创建数据库中的表。
此时,完整的文件将如下显示:
1[label sqlite_demo/db.js]
2const fs = require("fs");
3const sqlite3 = require("sqlite3").verbose();
4const filepath = "./fish.db";
5
6function createDbConnection() {
7 if (fs.existsSync(filepath)) {
8 return new sqlite3.Database(filepath);
9 } else {
10 const db = new sqlite3.Database(filepath, (error) => {
11 if (error) {
12 return console.error(error.message);
13 }
14 createTable(db);
15 });
16 console.log("Connection with SQLite has been established");
17 return db;
18 }
19}
20
21function createTable(db) {
22 db.exec(`
23 CREATE TABLE sharks
24 (
25 ID INTEGER PRIMARY KEY AUTOINCREMENT,
26 name VARCHAR(50) NOT NULL,
27 color VARCHAR(50) NOT NULL,
28 weight INTEGER NOT NULL
29 );
30`);
31}
32
33module.exports = createDbConnection();
保存并关闭您的文件,一旦完成更改。
要确保db.js
文件在多次运行时不会出现错误,请使用rm
命令删除fish.db
文件以重新启动:
1rm fish.db
运行db.js
文件:
1node db.js
1[secondary_label Output]
2Connection with SQLite has been established
现在,确认db.js
连接到数据库,并且不会尝试再次创建表,以便在db.js
文件的所有后续重启中重新运行该文件:
1node db.js
现在你会发现,你不会再犯错误了。
现在,您已连接到 SQLite 数据库并创建表,您将将数据插入到数据库中。
步骤 3 – 将数据插入 SQLite 数据库
在此步骤中,您将创建一个函数,使用node-sqlite3
模块将数据插入 SQLite 数据库,将您想要插入的数据作为命令行参数传递给程序。
在文本编辑器中创建并打开insertData.js
文件:
1nano insertData.js
在insertData.js
文件中,添加以下代码以获取命令行参数:
1[label sqlite_demo/insertData.js]
2const db = require("./db");
3
4function insertRow() {
5 const [name, color, weight] = process.argv.slice(2);
6}
在第一行中,您将导入您在前一步中导出的db.js
文件中的数据库对象。在第二行中,您将定义insertRow()
函数,您将很快使用该函数将数据插入表中。在函数中,process.argv
返回了 array中的所有命令行参数。指数0
上的第一个元素包含向节点的路径。指数1
上的第二个元素存储了JavaScript程序的文件名。从2
开始的所有后续元素都包含您将命令行参数传送到文件中。要跳过前两个参数,您可以使用JavaScript的slice()
方法将数组复制成浅的副本,并从2
接下来,添加突出代码将数据插入数据库:
1[label sqlite_demo/insertData.js]
2const db = require("./db");
3
4function insertRow() {
5 const [name, color, weight] = process.argv.slice(2);
6 db.run(
7 `INSERT INTO sharks (name, color, weight) VALUES (?, ?, ?)`,
8 [name, color, weight],
9 function (error) {
10 if (error) {
11 console.error(error.message);
12 }
13 console.log(`Inserted a row with the ID: ${this.lastID}`);
14 }
15 );
16}
在上一代代码中,你称之为 db.run()
方法,它需要三个参数: SQL 语句、数组和调用语句。第一个参数, INSERT INTO sharks...
,是将数据插入数据库的 SQL 语句。在 INSERT
语句中的 VALUES
语句中,需要插入的值单个列表。 请注意,你正在传输 ?
位数,而不是直接传输值。 这是为了避免 SQL injection 攻击。 在执行过程中,SQLite 会自动用在 `db.run()’ 方法中传输的值替换位数,这是一个包含命令行参数值的数组。
最后,db.run()
方法的第三个参数是当数据被成功插入到表中时运行的回调。如果出现错误,错误消息将登录到控制台中。
现在,添加突出的行来调用insertRow()
函数:
1[label sqlite_demo/insertData.js]
2const db = require("./db");
3
4function insertRow() {
5 const [name, color, weight] = process.argv.slice(2);
6 db.run(
7 `INSERT INTO sharks (name, color, weight) VALUES (?, ?, ?)`,
8 [name, color, weight],
9 function (error) {
10 if (error) {
11 console.error(error.message);
12 }
13 console.log(`Inserted a row with the ID: ${this.lastID}`);
14 }
15 );
16}
17
18insertRow();
保存并关闭您的文件,然后使用鲨鱼名称、颜色和重量参数运行文件:
1node insertData.js sammy blue 1900
输出表示该行已被插入到表中,其主要ID 1
:
1[secondary_label Output]
2Inserted a row with the ID: 1
使用不同的参数再次运行命令:
1node insertData.js max white 2100
1[secondary_label Output]
2Inserted a row with the ID: 2
当您运行之前的命令时,将在鲨鱼
表中创建两行。
现在您可以将数据插入 SQLite 数据库,接下来您将从数据库中获取数据。
步骤 4 – 从 SQLite 数据库中获取数据
在此步骤中,您将使用node-sqlite3
模块来检索 SQLite 数据库中的鲨鱼
表中存储的所有数据,并登录到控制台中。
首先,打开listData.js
文件:
1nano listData.js
在您的listData.js
文件中,添加以下代码来检索所有行:
1[label sqlite_demo/listData.js]
2const db = require("./db");
3
4function selectRows() {
5 db.each(`SELECT * FROM sharks`, (error, row) => {
6 if (error) {
7 throw new Error(error.message);
8 }
9 console.log(row);
10 });
11}
首先,您将数据库对象导入 db.js
文件中。 其次,您将定义 selectRows()
函数,该函数会检索 SQLite 数据库中的所有行。 在该函数中,您将使用数据库对象 db
的 each()
方法从数据库中一个接一个检索行。
第一个参数SELECT
返回了鲨鱼
表中的所有行。第二个参数是从数据库中检索一行时每次运行的回调。在回调中,您检查是否存在错误。
现在,添加突出的代码来调用‘selectRows()’函数:
1[label sqlite_demo/listData.js]
2const db = require("./db");
3
4function selectRows() {
5 db.each(`SELECT * FROM sharks`, (error, row) => {
6 if (error) {
7 throw new Error(error.message);
8 }
9 console.log(row);
10 });
11}
12
13selectRows();
保存和退出您的文件,然后运行文件:
1node listData.js
当运行命令时,您会注意到输出显示如下:
1[secondary_label Output]
2{ ID: 1, name: 'sammy', color: 'blue', weight: 1900 }
3{ ID: 2, name: 'max', color: 'white', weight: 2100 }
输出显示了您在上一步中插入的鲨鱼
表中的所有行. node-sqlite3
模块将每个SQL结果转换为JavaScript对象。
现在您可以从 SQLite 数据库中获取数据,您将更新 SQLite 数据库中的数据。
步骤 5 – 修改 SQLite 数据库中的数据
在此步骤中,您将使用node-sqlite3
模块更新 SQLite 数据库中的行. 要做到这一点,您将向程序传递一个命令行参数,其中包含您想要修改的行的主要 ID,以及您想要更新行的值。
在文本编辑器中创建并打开updateData.js
文件:
1nano updateData.js
在updateData.js
文件中,添加以下代码来更新记录:
1[label sqlite_demo/updateData.js]
2const db = require("./db");
3
4function updateRow() {
5 const [id, name] = process.argv.slice(2);
6 db.run(
7 `UPDATE sharks SET name = ? WHERE id = ?`,
8 [name, id],
9 function (error) {
10 if (error) {
11 console.error(error.message);
12 }
13 console.log(`Row ${id} has been updated`);
14 }
15 );
16}
17
18updateRow();
首先,您从db.js
文件中导入数据库对象;其次,您定义了updateRow
函数,该函数更新了数据库中的一个行。在该函数中,您将命令行参数解包成id
和name
变量。
接下来,您使用以下参数调用db.run()
函数:一个 SQL 语句和一个 callback。UPDATE
SQL 语句将name
列从当前值更改为name
变量中传递的值。WHERE
条款确保只有id
变量中的 ID 行才能更新。
最后,您将调用updateRow()
函数。
保存并关闭你的文件,当你完成更改。
运行updateData.js
文件,包含您想要更改的行id
和新的名称
:
1node updateData.js 2 sonny
1[secondary_label Output]
2Row 2 has been updated
查看是否已更改名称:
1node listData.js
当您运行该命令时,您的输出将如下:
1[secondary_label Output]
2{ ID: 1, name: 'sammy', color: 'blue', weight: 1900 }
3{ ID: 2, name: 'sonny', color: 'white', weight: 2100 }
输出表示,标识符号2
的行现在为其名称
字段的值具有sonny
。
通过此,您现在可以更新数据库中的一个行,然后您将从 SQLite 数据库中删除数据。
步骤 6 – 在 SQLite 数据库中删除数据
在本节中,您将使用node-sqlite3
从 SQLite 数据库中的表中选择和删除行。
在文本编辑器中创建并打开deleteData.js
文件:
1nano deleteData.js
在您的「deleteData.js」文件中,添加以下代码来删除数据库中的行:
1[label sqlite_demo/deleteData.js]
2const db = require("./db");
3
4async function deleteRow() {
5 const [id] = process.argv.slice(2);
6 db.run(`DELETE FROM sharks WHERE id = ?`, [id], function (error) {
7 if (error) {
8 return console.error(error.message);
9 }
10 console.log(`Row with the ID ${id} has been deleted`);
11 });
12}
13
14deleteRow();
首先,您将数据库对象导入db.js
文件中。第二,您定义了deleteRow()
来删除鲨鱼
表中的一个行。在函数中,您将主键ID解包并存储在id
变量中。接下来,您将召唤db.run()
,这需要两个参数。第一个参数是SQL语句DELETE from sharks...
来删除鲨鱼
表中的一个行。WHERE
条款确保只删除id
变量中的ID的行。第二个参数是在删除行后运行的调用。如果成功,函数会记录成功消息;否则,它会在控制台中记录错误。
最后,您将调用deleteRow()
函数。
保存并关闭您的文件,然后运行以下命令:
1node deleteData.js 2
1[secondary_label Output]
2Row with the ID 2 has been deleted
接下来,确认行已被删除:
1node listData.js
当您运行命令时,您的输出将显示如下:
1[secondary_label Output]
2{ ID: 1, name: 'sammy', color: 'blue', weight: 1900 }
标识符号2
的行不再在结果中,这表明该行已被删除。
通过此,您现在可以使用node-sqlite3
模块删除 SQLite 数据库中的行。
结论
在本文中,您创建了一个 Node.js 应用程序,该应用程序使用node-sqlite3
模块连接到并在 SQLite 数据库中创建表。
若要了解更多关于node-sqlite3
的方法,请访问 node-sqlite3’ Wiki 页面。 若要了解有关 SQLite 的信息,请参阅 SQLite 文档. 如果您想了解 SQLite 如何与其他 SQL 数据库进行比较,请参阅我们的教程 SQLite vs MySQL vs PostgreSQL: A Comparison Of Relational Database Management Systems. 若要继续您的 Node.js 旅程,请参阅 How To Code in Node.js series。