继上文,任务保存数据需要持久化,考虑使用的是sqlite3数据库。下面我们将看到如何在Node.js中设置sqlite3并对sqlite3数据库运行不同类型的SQL查询。
涵盖的主题
什么是SQLite
SQLite与Node.js之间的通信
检索所有行
检索单行
基于占位符检索数据
执行run()方法
使用SQLite each()方法代替forEach()
同步运行查询
什么是SQLite
SQLite是一个关系数据库。与数据库相关的详细信息存储在一个文件中。从一台机器向另一台机器复制数据库只是一个文件,没有复杂的命令或任何东西。只需传输该文件。
SQLite数据库非常轻量级,设置和使用非常简单。没有复杂的数据服务器设置或笨重的连接对象。
该数据库不适合由多个用户同时访问。由于数据存储在文件中,我们还需要注意安全性。此外,它不验证数据类型。
用于在不同类型的操作系统中设置SQLite的二进制文件。
DB浏览器用于以UI形式查看数据库,编写查询并执行查询。
将用于解释概念和方法的示例DB文件。
SQLite与Node.js之间的通信
在您的工作空间文件夹位置安装sqlite3。在cmd中运行以下命令
npm install sqlite3
在代码编辑器中导入sqlite3模块以促进它们之间的连接。
const sqlite3 = require('sqlite3');
该模块具有将帮助我们从Node.js与sqlite3通信的方法。
打开数据库,数据库在SQLite中是一个单独的文件,所以我们只需要传递数据库的路径。在这里,我们将使用上面提供的链接的DB文件。
const db = new sqlite3.Database('./chinook.db');
检索所有行
为了从DB获取信息,我们使用查询,查询是从数据库请求特定信息的语句。
要获取所有行,我们使用all()方法。该方法允许我们执行查询并调用回调以访问结果集中的行。
如果在执行查询时有任何问题,错误对象将包含错误详细信息,否则它将为null。 rows对象包含查询的结果。
const sqlite3 = require('sqlite3');
const db = new sqlite3.Database('./chinook.db');
//Retrieving All Rows
db.all("SELECT EmployeeId, FirstName FROM employees", (error, rows) => {
rows.forEach((row) => {
console.log(row.EmployeeId + " " + row.FirstName);
})
});
检索单行
在某些情况下,我们可能想检查查询是否正常工作,而不想检索所有结果,只检索一行就足够了。 此外,在某些情况下,我们可能确定查询将返回一行,例如基于主键进行查询。
在所有上述情况下,我们都可以使用get()方法。
const sqlite3 = require('sqlite3');
const db = new sqlite3.Database('./chinook.db');
//Retrieving A Single Row
db.get("SELECT EmployeeId, FirstName FROM employees", (error, row) => {
console.log(row.EmployeeId + " " + row.FirstName);
});
基于占位符检索数据
在查询中使用where条件时,我们可能希望向添加的条件传递动态值,否则如果不使用动态值,我们必须对其进行硬编码,这可能不是我们总是想要的情况。
为了满足上述情况,我们使用占位符,我们传递给占位符的值将在查询中替换,从而使其具有动态性质。
const sqlite3 = require('sqlite3');
const db = new sqlite3.Database('./chinook.db');
//Retrieving Data Based on Placeholder
db.all("SELECT EmployeeId, FirstName FROM employees where title=$title", {
$title: 'Sales Support Agent'
},
(error, rows) => {rows.forEach((row) => {
console.log(row.EmployeeId + " " + row.FirstName);
})
});
在这里,我们对标题使用了一个占位符来基于“销售支持代理”进行搜索,替换此值将更改查询而不必接触它。
执行run()方法
所有上述方法都会返回一些行作为结果,但有一些查询不会返回任何结果,例如创建表、删除表、插入行。
对于这些情况,我们使用run()方法。 它不会返回任何结果,但可能会在回调的作用域内向此关键字附加附加属性。 在插入行的情况下,它会将lastID附加到此,这是一个属性,用于存储最后插入的行ID的值。
const sqlite3 = require('sqlite3');
const db = new sqlite3.Database('./chinook.db');
//Executing run() Method
db.run(`INSERT INTO playlists(Name) VALUES(?)`,
['Rock'],
function(error){
console.log("New playlist added with id " + this.lastID);
}
);
使用SQLite each()方法而不是forEach()
可能有一种情况,我们希望对查询返回的所有行执行类似的操作。 在我们的db.all()方法示例中,我们使用javascript forEach()方法迭代每个行。
我们可以使用each()方法,该方法以查询和回调函数为参数,它将在结果的每一行上运行回调。
const sqlite3 = require('sqlite3');
const db = new sqlite3.Database('./chinook.db');
//Using SQLite each() Method Instead of forEach()
db.each("SELECT EmployeeId, FirstName FROM employees limit 10",
(error, row) => {
console.log(row.EmployeeId + " " + row.FirstName);
}
);
同步运行查询
假设有一个要求,您要删除一个表,然后创建一个表,然后插入一些行。 如果我们分别放置所有这些查询并执行它们,那么它们都将并行运行。 可能会发生删除查询已执行,在执行创建查询之前,插入查询已执行,这将导致错误。
上述场景也可以通过在上一个查询的回调中编写查询来解决。 类似地,插入查询可以进入创建表查询的回调中。
const sqlite3 = require('sqlite3');
const db = new sqlite3.Database('./chinook.db');
//Running Queries Synchronously without serialize method
db.run("DROP TABLE playlists", function(error){
db.run("CREATE TABLE playlists([PlaylistId] INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,[Name] NVARCHAR(120))", function(error){
db.run("INSERT INTO playlists (name) VALUES ('Music'), ('Movies'), ('TV Shows')");
});
});
然而,我们必须在前一个的回调中缩进下一个查询,在某些时候,它可能变得复杂难以处理。
为了避免上述类型的场景,我们需要以同步方式运行它们。 我们使用serialize()方法来实现这一点。
const sqlite3 = require('sqlite3');
const db = new sqlite3.Database('./chinook.db');
//with serialize method
db.serialize(() => {
db.run("DROP TABLE playlists");
db.run("CREATE TABLE playlists([PlaylistId] INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,[Name] NVARCHAR(120))");
db.run("INSERT INTO playlists (name) VALUES ('Music'), ('Movies'), ('TV Shows')");
});
希望这篇博文将帮助您了解与SQLite和Nodejs相关的概念和方法。