Logo
Section 1 / 3

将 PostgreSQL 与 Node.js 集成

学习如何使用 pg 模块将 Node.js 应用连接到 PostgreSQL,并执行基本的 CRUD 操作。

导入

将 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. 参数化查询: 使用占位符(例如 $1, $2)处理输入,将数据与查询逻辑分离。

  2. 输入验证: 对所有用户输入进行清洗和验证,确保其符合预期格式。

  3. 限制权限: 限制数据库用户的权限,仅允许必要的操作,以最小化潜在损害。

通过使用参数化查询,我们可以有效保护应用程序免受 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. 参数化查询: 使用占位符(例如 $1, $2)处理输入,将数据与查询逻辑分离。

  2. 输入验证: 对所有用户输入进行清洗和验证,确保其符合预期格式。

  3. 限制权限: 限制数据库用户的权限,仅允许必要操作,以最小化潜在损害。

通过使用参数化查询,我们可以有效保护应用程序免受 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 关闭数据库连接,确保程序干净退出。

显示提示

  1. 对于 addTask:

    1. 使用参数化查询和占位符(例如 $1, $2)防止 SQL 注入。

    2. 使用查询中的 RETURNING * 返回新插入的行。

  2. 对于 getTasks:

    1. 使用简单的 SELECT * FROM tasks 查询。

  3. 对于 updateTaskStatus:

    1. 使用 WHERE id = $1 更新匹配 id 的任务的 status 字段。

    2. 使用 RETURNING * 返回更新后的行。

  4. 对于 deleteTask:

    1. 删除与参数匹配的 id 的行。使用 RETURNING * 验证删除操作。

  1. 创建表:

    • 打开一个新终端,进入 my-project 目录并运行 dbSetup.js 文件:

      1node dbSetup.js
    • 此操作将在数据库中创建 tasks 表。

  2. 运行 CRUD 操作:

    • 执行 dbOperations.js 文件:

      1node dbOperations.js
    • 使用以下命令交叉验证数据库:

      1su - postgres -c "psql -d sampledb -c 'SELECT * FROM tasks;'"

npm 和包管理

使用 Node.js 和 PostgreSQL 构建 RESTful API