将 PostgreSQL 与 Node.js 集成
学习如何使用 pg 模块将 Node.js 应用连接到 PostgreSQL,并执行基本的 CRUD 操作。
代码示例
1npm install pg
代码示例
1cat package.json
连接 PostgreSQL 数据库的代码
1import pkg from 'pg'; // 在 ES6 语法中以 CommonJS 模块方式导入 pg 2const { Client } = pkg; 3 4const client = new Client({ 5 user: 'postgres', // PostgreSQL 用户名 6 host: 'localhost', // 数据库服务器地址 7 database: 'sampledb', // 数据库名称 8 password: 'pwd123', // 数据库用户的密码 9 port: 5432, // 默认 PostgreSQL 端口 10}); 11 12client.connect() 13 .then(() => console.log('已连接到 PostgreSQL')) 14 .catch((err) => console.error('连接错误', err)); 15 16export { client }; // 导出 client 对象
创建 users 表的代码
1import { client } from './config.js'; 2 3const setupDatabase = async () => { 4 const createUsersTableQuery = ` 5 CREATE TABLE IF NOT EXISTS users ( 6 id SERIAL PRIMARY KEY, 7 name TEXT NOT NULL, 8 email TEXT NOT NULL UNIQUE 9 ); 10 `; 11 12 try { 13 await client.query(createUsersTableQuery); 14 console.log('表 "users" 创建成功。'); 15 } catch (err) { 16 console.error('数据库设置错误:', err); 17 } finally { 18 await client.end(); 19 } 20}; 21 22setupDatabase();
代码示例
1node dbSetup.js
对 users 表执行 CRUD 操作
1import { client } from './config.js'; 2 3// 插入多个用户 4const insertUsers = async (users) => { 5 const query = 'INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *'; 6 7 try { 8 for (const user of users) { 9 const result = await client.query(query, [user.name, user.email]); 10 console.log('用户已添加:', result.rows[0]); 11 } 12 } catch (err) { 13 console.error('插入错误:', err); 14 } 15}; 16 17// 获取所有用户 18const getUsers = async () => { 19 const query = 'SELECT * FROM users'; 20 21 try { 22 const result = await client.query(query); 23 console.log('用户:', result.rows); 24 } catch (err) { 25 console.error('获取错误:', err); 26 } 27}; 28 29// 更新用户 30const updateUser = async (id, name) => { 31 const query = 'UPDATE users SET name = $1 WHERE id = $2 RETURNING *'; 32 const values = [name, id]; 33 34 try { 35 const result = await client.query(query, values); 36 console.log('用户已更新:', result.rows[0]); 37 } catch (err) { 38 console.error('更新错误:', err); 39 } 40}; 41 42// 删除用户 43const deleteUser = async (id) => { 44 const query = 'DELETE FROM users WHERE id = $1 RETURNING *'; 45 const values = [id]; 46 47 try { 48 const result = await client.query(query, values); 49 console.log('用户已删除:', result.rows[0]); 50 } catch (err) { 51 console.error('删除错误:', err); 52 } 53}; 54 55// 执行 CRUD 操作 56await insertUsers([ 57 { name: 'Alice', email: 'alice@example.com' }, 58 { name: 'Bob', email: 'bob@example.com' } 59]); 60await getUsers(); 61await updateUser(1, 'Alice Updated'); 62await deleteUser(2); 63 64// 关闭数据库连接 65await client.end();
代码示例
1node dbOperations.js
SQL 注入是一种安全漏洞,攻击者通过注入恶意输入来操纵 SQL 查询。这使得他们能够利用应用程序的漏洞,访问、修改或删除数据库中的敏感数据。
例如,考虑一个根据输入检索用户数据的查询,如 'alice':
1SELECT * FROM users WHERE username = 'alice';
如果未对用户输入进行验证,攻击者可能提供如下输入:
1' OR '1'='1
这将导致以下查询:
1SELECT * FROM users WHERE username = '' OR '1'='1';
由于 '1'='1' 始终评估为 TRUE,该查询会暴露表中的所有行,从而危及数据库。
如何防止 SQL 注入?
以下是几种防止 SQL 注入的方法:
-
参数化查询: 使用占位符(例如
$1,$2)处理输入,将数据与查询逻辑分离。 -
输入验证: 对所有用户输入进行清洗和验证,确保其符合预期格式。
-
限制权限: 限制数据库用户的权限,仅允许必要的操作,以最小化潜在损害。
通过使用参数化查询,我们可以有效保护应用程序免受 SQL 注入攻击。
SQL 注入是一种安全漏洞,攻击者通过注入恶意输入来操纵 SQL 查询。这使得他们能够利用应用程序的漏洞,访问、修改或删除数据库中的敏感数据。
例如,考虑一个根据输入检索用户数据的查询,如 'alice':
1SELECT * FROM users WHERE username = 'alice';
如果未对用户输入进行验证,攻击者可能提供如下输入:
1' OR '1'='1
这将导致以下查询:
1SELECT * FROM users WHERE username = '' OR '1'='1';
由于 '1'='1' 始终评估为 TRUE,该查询会暴露表中的所有行,从而危及数据库。
如何防止 SQL 注入?
以下是几种防止 SQL 注入的方法:
-
参数化查询: 使用占位符(例如
$1,$2)处理输入,将数据与查询逻辑分离。 -
输入验证: 对所有用户输入进行清洗和验证,确保其符合预期格式。
-
限制权限: 限制数据库用户的权限,仅允许必要操作,以最小化潜在损害。
通过使用参数化查询,我们可以有效保护应用程序免受 SQL 注入攻击。
代码示例
1service postgresql status
-
步骤 1:安装包
-
使用以下命令安装
pg包:1npm install pg -
通过执行以下命令验证模块是否列在
package.json的 dependencies 中:1cat package.json
-
-
步骤 2:创建
users表-
点击“+”标签打开新终端。进入
my-project目录并运行dbSetup.js文件以创建users表:1node dbSetup.js -
如果
users表创建成功,将显示以下消息:1表 'users' 创建成功。
-
-
步骤 3:对数据库执行 CRUD 操作
-
运行
dbOperations.js文件以对users表执行 CRUD 操作:1node dbOperations.js -
输出应在终端中显示 INSERT、SELECT、UPDATE 和 DELETE 操作的结果。
-
-
我们可以通过在终端中运行以下命令直接查询
users表以查看其数据:1su - postgres -c "psql -d sampledb -c 'SELECT * FROM users;'"
-
步骤 1:安装包
-
使用以下命令安装
pg包:1npm install pg -
通过执行以下命令验证模块是否列在
package.json的 dependencies 中:1cat package.json
-
-
步骤 2:创建
users表-
点击“+”标签打开新终端。进入
my-project目录并运行dbSetup.js文件以创建users表:1node dbSetup.js -
如果
users表创建成功,将显示以下消息:1表 'users' 创建成功。
-
-
步骤 3:对数据库执行 CRUD 操作
-
运行
dbOperations.js文件以对users表执行 CRUD 操作:1node dbOperations.js -
输出应在终端中显示 INSERT、SELECT、UPDATE 和 DELETE 操作的结果。
-
-
我们可以通过在终端中运行以下命令直接查询
users表以查看其数据:1su - postgres -c "psql -d sampledb -c 'SELECT * FROM users;'"
No configuration found for ID: 86efb7319d58b0b68d881232c1b8c9e8052118e07a390685eed0a3b2b46a71e4
No configuration found for ID: 3c6eea6ce30b439063a3a85b9c7744476588997b6a89ef4128776e495e846316
显示解决方案
以下为 dbOperations.js 的代码:
对 tasks 表执行 CRUD 操作
1import { client } from './config.js'; 2 3// 插入新任务 4const addTask = async (title, description) => { 5 const query = 'INSERT INTO tasks (title, description) VALUES ($1, $2) RETURNING *'; 6 const values = [title, description]; 7 8 try { 9 const result = await client.query(query, values); 10 console.log('任务已添加:', result.rows[0]); 11 } catch (err) { 12 console.error('插入错误:', err); 13 } 14}; 15 16// 获取所有任务 17const getTasks = async () => { 18 const query = 'SELECT * FROM tasks'; 19 20 try { 21 const result = await client.query(query); 22 console.log('任务:', result.rows); 23 } catch (err) { 24 console.error('获取错误:', err); 25 } 26}; 27 28// 更新任务状态 29const updateTaskStatus = async (id, status) => { 30 const query = 'UPDATE tasks SET status = $1 WHERE id = $2 RETURNING *'; 31 const values = [status, id]; 32 33 try { 34 const result = await client.query(query, values); 35 console.log('任务已更新:', result.rows[0]); 36 } catch (err) { 37 console.error('更新错误:', err); 38 } 39}; 40 41// 删除任务 42const deleteTask = async (id) => { 43 const query = 'DELETE FROM tasks WHERE id = $1 RETURNING *'; 44 const values = [id]; 45 46 try { 47 const result = await client.query(query, values); 48 console.log('任务已删除:', result.rows[0]); 49 } catch (err) { 50 console.error('删除错误:', err); 51 } 52}; 53 54// 示例用法(用于测试) 55await addTask('完成作业', '完成数学练习'); 56await addTask('计划假期', '研究航班和酒店'); 57await getTasks(); 58await updateTaskStatus(1, '已完成'); 59await deleteTask(1); 60 61// 关闭数据库连接 62await client.end();
-
第 1 行: 从
config.js导入client对象,以复用数据库连接。 -
插入函数(
addTask)-
第 4 行: 将
addTask函数声明为async,以便使用await执行插入查询。 -
第 5 行: 定义参数化查询,将新任务插入
tasks表。查询使用占位符($1,$2)以防止 SQL 注入。 -
第 6 行: 将
title和description值作为数组传递,以替换查询中的占位符。 -
第 8–10 行: 执行查询并将插入的任务记录输出到控制台。
-
第 11–13 行: 捕获插入过程中可能出现的任何错误并记录。
-
-
获取函数(
getTasks)-
第 17 行: 声明
getTasks函数以从tasks表中获取所有行。 -
第 18 行: 使用简单的
SELECT * FROM tasks查询获取所有数据。 -
第 20–25 行: 执行查询并输出任务列表,或记录遇到的任何错误。
-
-
更新函数(
updateTaskStatus)-
第 29 行: 声明
updateTaskStatus函数,根据任务的id修改其status。 -
第 30 行: 定义参数化查询,更新特定任务的
status字段。 -
第 31 行: 将
status和id值传递给查询占位符。 -
第 33–38 行: 执行查询,输出更新后的任务,或在出现错误时记录。
-
-
删除函数(
deleteTask)-
第 42 行: 声明
deleteTask函数,根据任务的id删除任务。 -
第 43 行: 定义参数化查询,从
tasks表中删除任务。 -
第 44 行: 将
id值传递给查询占位符。 -
第 46–51 行: 执行查询并输出被删除的任务,或在操作失败时记录错误。
-
-
执行块
-
第 55–59 行: 依次调用 CRUD 函数并传入测试数据,包括插入任务、获取所有任务、更新任务状态以及删除任务。
-
第 62 行: 使用
client.end关闭数据库连接,确保程序干净退出。
-
-
第 1 行: 从
config.js导入client对象,以复用数据库连接。 -
插入函数(
addTask)-
第 4 行: 将
addTask函数声明为async,以便使用await执行插入查询。 -
第 5 行: 定义参数化查询,将新任务插入
tasks表。查询使用占位符($1,$2)以防止 SQL 注入。 -
第 6 行: 将
title和description值作为数组传递,以替换查询中的占位符。 -
第 8–10 行: 执行查询并将插入的任务记录输出到控制台。
-
第 11–13 行: 捕获插入过程中可能出现的任何错误并记录。
-
-
获取函数(
getTasks)-
第 17 行: 声明
getTasks函数以从tasks表中获取所有行。 -
第 18 行: 使用简单的
SELECT * FROM tasks查询获取所有数据。 -
第 20–25 行: 执行查询并输出任务列表,或记录遇到的任何错误。
-
-
更新函数(
updateTaskStatus)-
第 29 行: 声明
updateTaskStatus函数,根据任务的id修改其status。 -
第 30 行: 定义参数化查询,更新特定任务的
status字段。 -
第 31 行: 将
status和id值传递给查询占位符。 -
第 33–38 行: 执行查询,输出更新后的任务,或在出现错误时记录。
-
-
删除函数(
deleteTask)-
第 42 行: 声明
deleteTask函数,根据任务的id删除任务。 -
第 43 行: 定义参数化查询,从
tasks表中删除任务。 -
第 44 行: 将
id值传递给查询占位符。 -
第 46–51 行: 执行查询并输出被删除的任务,或在操作失败时记录错误。
-
-
执行块
-
第 55–59 行: 依次调用 CRUD 函数并传入测试数据,包括插入任务、获取所有任务、更新任务状态以及删除任务。
-
第 62 行: 使用
client.end关闭数据库连接,确保程序干净退出。
-
显示提示
对于
addTask:使用参数化查询和占位符(例如
$1,$2)防止 SQL 注入。使用查询中的
RETURNING *返回新插入的行。
对于
getTasks:使用简单的
SELECT * FROM tasks查询。
对于
updateTaskStatus:使用
WHERE id = $1更新匹配id的任务的status字段。使用
RETURNING *返回更新后的行。
对于
deleteTask:删除与参数匹配的
id的行。使用RETURNING *验证删除操作。
-
创建表:
-
打开一个新终端,进入
my-project目录并运行dbSetup.js文件:1node dbSetup.js -
此操作将在数据库中创建
tasks表。
-
-
运行 CRUD 操作:
-
执行
dbOperations.js文件:1node dbOperations.js -
使用以下命令交叉验证数据库:
1su - postgres -c "psql -d sampledb -c 'SELECT * FROM tasks;'"
-