如何在Ubuntu 22.04上使用Node.js使用SQLite

简介

SQLite是一种流行的开源SQL数据库引擎,用于存储数据。它是无服务器的,意味着它不需要服务器运行,而是将数据读写到计算机硬盘上的文件中。此外,SQLite不需要任何配置,这使它更加便携,成为嵌入式系统、桌面/移动应用和原型制作等领域的流行选择。

要在Node.js中使用SQLite,您需要一个连接到SQLite数据库并将应用程序中的SQL语句发送到数据库以执行的数据库客户端。其中一个受欢迎的选择是node-sqlite3包,它提供了SQLite 3的异步绑定。

在本教程中,您将使用node-sqlite3创建与SQLite数据库的连接。接下来,您将创建一个Node.js应用程序,在数据库中创建一个表并插入数据。最后,您将修改应用程序,使用node-sqlite3从数据库中检索、更新和删除数据。

先决条件

要按照这个教程进行操作,您需要准备以下物品:

  • A Node.js development environment set up on your system. If you are using Ubuntu 22.04, install the latest version of Node.js by following Option 3 of our tutorial How To Install Node.js on Ubuntu 22.04. For other systems, consult our tutorial series How to Install Node.js and Create a Local Development Environment.
  • SQLite3 installed on your development environment. Follow Step 1 of our tutorial How To Install and Use SQLite on Ubuntu 20.04.
  • Basic knowledge of how to create tables and write SQL queries to retrieve and modify data in a table. Follow Steps 2 through 6 of our tutorial How To Install and Use SQLite on Ubuntu 20.04.
  • Familiarity with how to write a Node.js program, which you can find in our tutorial How To Write and Run Your First Program in Node.js.

第一步 – 设置项目目录

在这个步骤中,您将创建项目目录并将node-sqlite3作为依赖下载。

首先,使用mkdir命令创建一个目录。这个教程将其称为sqlite_demo,但你可以用你选择的名称替换它。

  1. mkdir sqlite_demo

 

接下来,使用cd命令切换到新创建的目录。

  1. cd sqlite_demo

 

使用npm命令将项目目录初始化为npm包。

  1. npm init -y

 

该命令创建一个package.json文件,其中包含了项目的重要元数据。-y选项告诉npm接受所有默认设置。

运行命令后,以下输出将显示在您的屏幕上:

Output

Wrote to /home/sammy/sqlite_demo/package.json: { “name”: “sqlite_demo”, “version”: “1.0.0”, “description”: “”, “main”: “index.js”, “scripts”: { “test”: “echo \”Error: no test specified\” && exit 1″ }, “keywords”: [], “author”: “”, “license”: “ISC” }

输出结果表明已创建了package.json文件,其中包含记录项目重要元数据的属性。其中一些重要选项包括:

  • name: the name of your project.
  • version: your project version.
  • main: the starting point for your project.

您可以保留默认选项,但可以根据个人喜好修改属性值。如需了解更多属性信息,请参考npm的package.json文档。

接下来,使用npm install命令安装node-sqlite3软件包。

  1. npm install sqlite3

 

安装软件包后,输出将如下显示:

Output

added 104 packages, and audited 105 packages in 9s 5 packages are looking for funding run `npm fund` for details found 0 vulnerabilities

现在你已经安装了node-sqlite3,你将在下一节中使用它来连接SQLite数据库。

步骤2 – 连接到SQLite数据库

在这一步中,您将使用node-sqlite3将您的Node.js程序与一个包含不同鲨鱼及其属性的SQLite数据库连接起来。要建立数据库连接,node-sqlite3包提供了一个Database类。当实例化该类时,该类会在您的计算机硬盘上创建一个SQLite数据库文件并连接到它。一旦建立了连接,您将为应用程序创建一个表,在后面的部分中您将使用该表来插入、检索或更新数据。

使用nano或者你喜欢的文本编辑器,创建并打开db.js文件。

  1. nano db.js

 

在你的db.js文件中,添加以下代码来建立与SQLite数据库的连接。

sqlite_demo/db.js文件
const sqlite3 = require("sqlite3").verbose();
const filepath = "./fish.db";

function createDbConnection() {
  const db = new sqlite3.Database(filepath, (error) => {
    if (error) {
      return console.error(error.message);
    }
  });
  console.log("Connection with SQLite has been established");
  return db;
}

在第一行中,将node-sqlite3模块引入到您的程序文件中。在第二行中,使用您想要SQLite数据库所在的路径和数据库文件的名称(在这种情况下是fish.db)设置变量filepath。

在下一行中,您定义了createDbConnection()函数,该函数与SQLite数据库建立连接。在函数内部,您使用new关键字实例化了sqlite3.Database()类。该类接受两个参数:文件路径和回调函数。

第一个参数是文件路径,接受SQLite数据库的名称和路径,这里是./fish.db。第二个参数是回调函数,在数据库被创建并建立数据库连接后运行。回调函数接受一个错误参数,如果尝试建立数据库连接时发生错误,这个参数将被设为一个错误对象。在回调函数中,你可以使用if语句检查是否有错误发生。如果条件为真,你可以使用console.error()方法记录错误消息。

现在,当你使用sqlite3.Database()类创建一个实例时,它会在你的项目目录中创建一个SQLite数据库文件,并返回一个存储在db变量中的数据库对象。该数据库对象提供了可以用来传递SQL语句来创建表格以及插入、检索或修改数据的方法。

最后,你使用console.log()来输出成功消息,并将db变量中的数据库对象返回。

接下来,将高亮代码添加到创建表格的函数中。

sqlite_demo/db.js 的中文翻译:sqlite_demo/数据库.js
...
function createDbConnection() {
    ...
}

function createTable(db) {
  db.exec(`
  CREATE TABLE sharks
  (
    ID INTEGER PRIMARY KEY AUTOINCREMENT,
    name   VARCHAR(50) NOT NULL,
    color   VARCHAR(50) NOT NULL,
    weight INTEGER NOT NULL
  );
`);
}

createTable() 函数在 SQLite 数据库中创建一个表。它以数据库对象 db 作为参数。在 createTable() 函数内部,你调用了 db 数据库对象的 exec() 方法,将给定的 SQL 语句发送到数据库以供执行。exec() 方法仅用于不返回结果行的查询。

传递给exec()方法的CREATE TABLE sharks… SQL语句创建了一个名为sharks的表,该表具有以下字段:

  • ID: stores values of INTEGER datatype. The PRIMARY KEY constraint designates the column as the primary key and AUTOINCREMENT instructs SQLite to automatically increment the ID column values for each row in the table.
  • name: details the name of the shark using the VARCHAR datatype that has a maximum of 50 characters. The NOT NULL constraint ensures that the field cannot store NULL values.
  • color: represents the color of the shark using the VARCHAR datatype with a maximum of 50 characters. The NOT NULL constraint signifies that the field should not accept NULL values.
  • weight: stores the weight of the shark in kilograms using the INTEGER datatype, and uses the NOT NULL constraint to ensure that NULL values are not allowed.

在同一个db.js文件中,添加以下突出显示的代码来调用createTable()函数:

sqlite_demo/db.js 文件.
function createDbConnection() {
  const db = new sqlite3.Database(filepath, (error) => {
    if (error) {
      return console.error(error.message);
    }
    createTable(db);
  });
  console.log("Connection with SQLite has been established");
  return db;
}


function createTable(db) {
    ...
}

当回调运行时,你调用createTable()函数,并将db数据库对象作为参数传递进去。

接下来,将以下代码行添加到调用createDbConnection()函数:

...
function createDbConnection() {
    ...
}


function createTable(db) {
    ...
}

module.exports = createDbConnection();

在之前的代码中,你调用了createDbConnection()函数,该函数建立了与数据库的连接并返回一个数据库对象。然后你使用module.exports将数据库对象导出,这样你就可以在其他文件中引用它。

您的文件现在将包含以下内容:

sqlite_demo/db.js的中文释义
const sqlite3 = require("sqlite3").verbose();
const filepath = "./fish.db";

function createDbConnection() {
  const db = new sqlite3.Database(filepath, (error) => {
    if (error) {
      return console.error(error.message);
    }
    createTable(db);
  });
  console.log("Connection with SQLite has been established");
  return db;
}

function createTable(db) {
  db.exec(`
  CREATE TABLE sharks
  (
    ID INTEGER PRIMARY KEY AUTOINCREMENT,
    name   VARCHAR(50) NOT NULL,
    color   VARCHAR(50) NOT NULL,
    weight INTEGER NOT NULL
  );
`);
}

module.exports = createDbConnection();

保存并退出文件。如果使用nano编辑器,请按下CTRL+X退出,按下y保存你所做的更改,并按下ENTER键确认文件名。

使用node命令运行db.js文件。

  1. node db.js

 

输出结果将显示数据库连接已成功建立。

Output

Connection with SQLite has been established

接下来,使用ls命令检查是否已创建fish.db数据库文件。

  1. ls

 

Output

db.js fish.db node_modules package-lock.json package.json

鱼.db数据库文件在输出中的出现证实了数据库的成功创建。

现在,每次运行db.js文件,都会调用createTable()函数在数据库中创建一张表。尝试创建已经存在的表会触发SQLite抛出一个错误。要查看这一点,请使用节点命令重新运行db.js文件。

  1. node db.js

 

这一次,在接下来的输出中,你将会得到一个错误。

Output

Connection with SQLite has been established undefined:0 [Error: SQLITE_ERROR: table sharks already exists Emitted ‘error’ event on Database instance at: ] { errno: 1, code: ‘SQLITE_ERROR’ } Node.js v17.6.0

错误信息表明鲨鱼表已经存在。这是因为当您第一次运行节点命令时,鱼数据库和鲨鱼表已经创建。当您重新运行该命令时,createTable() 函数会再次运行,这将触发错误,因为该表已经存在。

每当您想要在其他文件中使用数据库对象方法操作数据库时,也会触发此错误。例如,在下一步中,您将创建一个将数据插入数据库的文件。为了使用数据库对象,您将导入 db.js 文件并调用相应的插入数据方法。当您运行该文件时,它将依次运行 db.js,从而触发相同的错误。

为了解决这个问题,你可以使用fs模块的existsSync()方法检查项目目录中是否存在名为fish.db的数据库文件。如果数据库文件存在,你将建立与数据库的连接而不调用createTable()函数。如果不存在,你将建立连接并调用createTable()函数。

为了做到这一点,请再次在您的编辑器中打开db.js文件。

  1. nano db.js

 

在你的db.js文件中,添加标记代码以检查数据库文件的存在。

sqlite_demo/db.js 的中文意思是什么?
const fs = require("fs");
const sqlite3 = require("sqlite3").verbose();
const filepath = "./fish.db";

function createDbConnection() {
  if (fs.existsSync(filepath)) {
    return new sqlite3.Database(filepath);
  } else {
    const db = new sqlite3.Database(filepath, (error) => {
      if (error) {
        return console.error(error.message);
      }
      createTable(db);
    });
    console.log("Connection with SQLite has been established");
    return db;
  }
}

首先,您导入用于与文件系统交互的fs模块。其次,在添加的if语句中,您调用fs.existSync()方法来检查给定参数中文件(此处为./fish.db)的存在性。如果文件存在,您会使用数据库文件路径调用sqlite3.Database(),并省略回调函数。然而,如果文件不存在,您将在回调函数中创建数据库实例,并调用createTable()函数来创建数据库中的表。

此时,完整的文件将会如下所示:

sqlite_demo/db.js

SQLite_demo/db.js

const fs = require("fs");
const sqlite3 = require("sqlite3").verbose();
const filepath = "./fish.db";

function createDbConnection() {
  if (fs.existsSync(filepath)) {
    return new sqlite3.Database(filepath);
  } else {
    const db = new sqlite3.Database(filepath, (error) => {
      if (error) {
        return console.error(error.message);
      }
      createTable(db);
    });
    console.log("Connection with SQLite has been established");
    return db;
  }
}

function createTable(db) {
  db.exec(`
  CREATE TABLE sharks
  (
    ID INTEGER PRIMARY KEY AUTOINCREMENT,
    name   VARCHAR(50) NOT NULL,
    color   VARCHAR(50) NOT NULL,
    weight INTEGER NOT NULL
  );
`);
}

module.exports = createDbConnection();

完成更改后,请保存并关闭您的文件。

为了确保在多次运行时,db.js文件不会出错,请使用rm命令删除fish.db文件以重新开始。

  1. rm fish.db

 

运行db.js文件。

  1. node db.js

 

Output

Connection with SQLite has been established

现在,运行db.js文件以确认其是否连接到数据库,并且在所有后续重新运行db.js文件时不会再次尝试创建表格。

  1. node db.js

 

你现在会注意到,你再也不会遇到错误了。

既然你已经建立了与SQLite数据库的连接并创建了一个表格,那么接下来你将向数据库插入数据。

第三步-将数据插入SQLite数据库

在这一步中,您将使用node-sqlite3模块创建一个函数,以将数据插入SQLite数据库。您将通过命令行参数将要插入的数据传递给程序。

在你的文本编辑器中创建并打开insertData.js文件。

  1. nano insertData.js

 

在你的insertData.js文件中,添加以下代码以获取命令行参数:

sqlite_demo/insertData.js可以插入数据。
const db = require("./db");

function insertRow() {
  const [name, color, weight] = process.argv.slice(2);
}

在第一行中,你导入了在上一步中在db.js文件中导出的数据库对象。在第二行中,你定义了函数insertRow(),你将很快用它来插入数据到表中。在这个函数中,process.argv以数组的形式返回所有的命令行参数。在索引0上的第一个元素包含Node的路径。在索引1上的第二个元素存储了JavaScript程序文件的名称。从索引2开始的所有后续元素包含你传递给文件的命令行参数。为了跳过前两个参数,你使用JavaScript的slice()方法来创建数组的一个浅拷贝,并从索引2开始返回数组的末尾处的元素。

接下来,将以下代码添加到数据库中以插入数据:

sqlite_demo/insertData.js 的意思是插入数据到 SQLite 数据库的演示。
const db = require("./db");

function insertRow() {
  const [name, color, weight] = process.argv.slice(2);
  db.run(
    `INSERT INTO sharks (name, color, weight) VALUES (?, ?, ?)`,
    [name, color, weight],
    function (error) {
      if (error) {
        console.error(error.message);
      }
      console.log(`Inserted a row with the ID: ${this.lastID}`);
    }
  );
}

在前面的代码中,您调用了db.run()方法,它接受三个参数:SQL语句、一个数组和一个回调函数。第一个参数INSERT INTO sharks…是一个将数据插入数据库的SQL语句。在INSERT语句中的VALUES语句中,您传递一个用逗号分隔的值列表,这些值需要被插入。请注意,您传递的是?占位符,而不是直接传递值。这是为了避免SQL注入攻击。在执行过程中,SQLite会自动用db.run()方法的第二个参数中包含的命令行参数值替换占位符,该参数是一个包含值的数组。

最后,db.run() 方法的第三个参数是一个回调函数,在数据成功插入表格后运行。如果出现错误,错误消息会被记录在控制台中。如果插入成功,你将使用返回的 this.lastID 记录新插入行的 ID,同时打印出成功的信息。

现在,将高亮的行添加到调用insertRow()函数的位置。

sqlite_demo/insertData.js的中文释义
const db = require("./db");

function insertRow() {
  const [name, color, weight] = process.argv.slice(2);
  db.run(
    `INSERT INTO sharks (name, color, weight) VALUES (?, ?, ?)`,
    [name, color, weight],
    function (error) {
      if (error) {
        console.error(error.message);
      }
      console.log(`Inserted a row with the ID: ${this.lastID}`);
    }
  );
}

insertRow();

保存并关闭您的文件,然后使用鲨鱼名称、颜色和重量参数运行文件。

  1. node insertData.js sammy blue 1900

 

输出表明已将行插入到具有主要ID 1的表中。

Output

Inserted a row with the ID: 1

用不同的参数再次运行该命令。

  1. node insertData.js max white 2100

 

Output

Inserted a row with the ID: 2

当您运行前面的命令时,将在sharks表中创建两行记录。

现在,你已经可以将数据插入到SQLite数据库中了,接下来你将从数据库中检索数据。

第四步 – 从SQLite数据库中检索数据

在这一步中,您将使用node-sqlite3模块从SQLite数据库中检索存储在sharks表中的所有数据,并将它们记录在控制台中。

首先,打开listData.js文件。

  1. nano listData.js

 

在你的listData.js文件中,添加以下代码以检索所有行:

sqlite_demo/listData.js的翻译:
数据库演示/列出数据.js
const db = require("./db");

function selectRows() {
  db.each(`SELECT * FROM sharks`, (error, row) => {
    if (error) {
      throw new Error(error.message);
    }
    console.log(row);
  });
}

首先,在db.js文件中导入数据库对象。其次,定义selectRows()函数,该函数从SQLite数据库中检索所有行。在函数内部,使用数据库对象db的each()方法逐行检索数据库中的行。each()方法接受两个参数:SQL语句和回调函数。

第一个参数SELECT返回sharks表中的所有行。第二个参数是一个回调函数,它在从数据库检索每一行时运行。在回调函数中,您检查是否有错误。如果有错误,您使用throw语句创建一个自定义错误。如果在检索过程中没有发生错误,则将数据记录在控制台中。

现在,将高亮显示的代码添加到调用selectRows()函数的位置。

sqlite_demo/listData.js 的中文翻译为:“SQLite演示/列表数据.js”。
const db = require("./db");

function selectRows() {
  db.each(`SELECT * FROM sharks`, (error, row) => {
    if (error) {
      throw new Error(error.message);
    }
    console.log(row);
  });
}

selectRows();

保存并退出你的文件,然后运行文件。

  1. node listData.js

 

执行该命令后,您会注意到以下显示的输出。

Output

{ ID: 1, name: ‘sammy’, color: ‘blue’, weight: 1900 } { ID: 2, name: ‘max’, color: ‘white’, weight: 2100 }

在前一步中,输出显示了您在鲨鱼表中插入的所有行。node-sqlite3模块将每个SQL结果转换为JavaScript对象。

现在你已经可以从SQLite数据库中检索数据,你将更新SQLite数据库中的数据。

第五步 —— 在SQLite数据库中修改数据

在这个步骤中,您将使用node-sqlite3模块更新SQLite数据库中的一行。为了做到这一点,您将向程序传递一个包含您想要修改的行的主要ID以及您想要将该行更新为的值的命令行参数。

在您的文本编辑器中创建并打开updateData.js文件。

  1. nano updateData.js

 

在您的updateData.js文件中,添加以下代码来更新一条记录:

sqlite_demo/updateData.js 的中文顺口溜至一种选择的改写方式:
sqlite示例/更新数据.js
const db = require("./db");

function updateRow() {
  const [id, name] = process.argv.slice(2);
  db.run(
    `UPDATE sharks SET name = ? WHERE id = ?`,
    [name, id],
    function (error) {
      if (error) {
        console.error(error.message);
      }
      console.log(`Row ${id} has been updated`);
    }
  );
}

updateRow();

首先,你从db.js文件中导入数据库对象。其次,你定义了一个名为updateRow的函数,该函数用于更新数据库中的某一行。在函数内部,你将命令行参数解包到id和name变量中。id变量包含你想要更新的行的主键ID,而name变量则包含你想要将name字段反映的值。

接下来,您使用以下参数调用db.run()函数:一个SQL语句和一个回调函数。UPDATE SQL语句将名称列从当前值更改为name变量中传递的值。WHERE子句确保只有ID变量中的行被更新。db.run()方法接受第二个参数,这是一个在值更新后运行的回调函数。

最后,你调用 updateRow() 函数。

当您完成了更改后,请保存并关闭文件。

用要更改的行的id和新名称运行updateData.js文件。

  1. node updateData.js 2 sonny

 

Output

Row 2 has been updated

确认姓名已经更改

  1. node listData.js

 

当你运行该命令时,你的输出将类似于以下内容:

Output

{ ID: 1, name: ‘sammy’, color: ‘blue’, weight: 1900 } { ID: 2, name: ‘sonny‘, color: ‘white’, weight: 2100 }

输出表明,具有ID 2的行现在将”Sonny”作为其姓名字段的值。

有了这个,你现在可以在数据库中更新一行数据。接下来,你将会从SQLite数据库中删除数据。

步骤6 — 删除 SQLite 数据库中的数据

在本节中,您将使用node-sqlite3来从SQLite数据库中选择和删除表中的一行数据。

在文本编辑器中创建并打开 deleteData.js 文件。

  1. nano deleteData.js

 

在您的deleteData.js文件中,添加以下代码以删除数据库中的一行数据:

删除数据demo的JavaScript文件:sqlite_demo/deleteData.js。
const db = require("./db");

async function deleteRow() {
  const [id] = process.argv.slice(2);
  db.run(`DELETE FROM sharks WHERE id = ?`, [id], function (error) {
    if (error) {
      return console.error(error.message);
    }
    console.log(`Row with the ID ${id} has been deleted`);
  });
}

deleteRow();

首先,在db.js文件中导入数据库对象。其次,你定义了一个deleteRow()函数,该函数用于删除表sharks中的一行。在函数内部,你解构主键ID并将其存储在id变量中。接下来,你调用db.run()方法,该方法需要两个参数。第一个参数是SQL语句DELETE from sharks…,它用于删除表sharks中的一行。WHERE子句确保只删除id变量中包含的主键ID的行。第二个参数是一个回调函数,它会在行被删除后运行。如果删除成功,该函数会记录一条成功消息;否则,它会将错误记录在控制台中。

最后,你调用deleteRow()函数。

保存并关闭您的文件,然后运行以下命令。

  1. node deleteData.js 2

 

Output

Row with the ID 2 has been deleted

接下来,请确认该行已被删除。

  1. node listData.js

 

当你运行该命令时,你的输出将以类似以下的方式显示:

Output

{ ID: 1, name: ‘sammy’, color: ‘blue’, weight: 1900 }

ID为2的行已经不在结果中了。这证实了该行已被删除。

有了这个,你现在可以使用node-sqlite3模块在SQLite数据库中删除行了。

结论

在本文中,您创建了一个使用node-sqlite3模块连接到SQLite数据库并创建表的Node.js应用程序。接下来,您修改了该应用程序以在数据库中插入、检索和更新数据。最后,您修改了该应用程序以删除数据库中的数据。

想要深入了解node-sqlite3方法,请访问node-sqlite3维基页面。要了解SQLite,请查阅SQLite文档。如果你想了解SQLite与其他SQL数据库的比较,请参阅我们的教程:《SQLite vs MySQL vs PostgreSQL:关系数据库管理系统的比较》。要继续学习Node.js的旅程,请访问《如何在Node.js中编码》系列教程。

发表回复 0

Your email address will not be published. Required fields are marked *


广告
将在 10 秒后关闭
bannerAds