← MySQL 更新数据 MySQL 读取数据 →

Node.js mysql2执行MySQL DELETE删除数据教程:单条、批量、参数化查询与affectedRows

著
原创 2026-10-13 Node.js 已有人查阅

为什么删除操作值得单独拿出来讲

增删改查四个动作里,删除往往是最容易被轻视的一个。很多开发者觉得DELETE不就是DELETEFROM表WHERE条件吗,有什么好说的。实际项目里出问题的恰恰是删除:WHERE条件写漏导致全表清空、表名拼错导致接口报错、用户输入直接拼接SQL导致注入、删完之后不判断affectedRows导致前端提示“删除成功”但数据根本没动。

这篇文章围绕Node.js+mysql2操作MySQL的DELETE语句展开,把删除这件事讲透。

先分清DELETE和DROPTABLE

这两个语句经常被混淆,但做的事情不同。

DELETE是DML(数据操作语言),它删除的是表中的行记录,表结构、列定义、索引、约束都保留。删完之后表还在,只是数据少了。

DROPTABLE是DDL(数据定义语言),它直接把整张表连结构带数据一起抹掉,表本身不复存在。

-- 只删 id 为 1 的那条员工记录,表还在
DELETE FROM employees WHERE id = 1;

-- 整张 employees 表消失,结构和数据都没了
DROP TABLE employees;

项目里做业务删除时用的是DELETE,DROPTABLE一般只在迁移脚本或清理废弃表时出现。把这两个搞混,后果不是删错一行数据,而是整张表没了。

DELETE的基本语法与WHERE的重要性

DELETE FROM table_name WHERE condition;

table_name指定从哪张表删,WHERE指定删哪些行。

这里有一条必须记住的规则:WHERE子句决定了删除的范围,省略WHERE就是删除全表所有记录。MySQL不会因为你没写WHERE就拒绝执行,它会老老实实把整张表清空。所以生产环境执行DELETE之前,先把这个条件对应的SELECT跑一遍,看看选出来的行数对不对,再换成DELETE。

环境准备

动手之前确认几件事:

  • 系统已安装Node.js

  • MySQLServer已安装并处于运行状态

  • 项目里已安装mysql2包

  • 目标数据库和employees表已存在

安装mysql2:

npm install mysql2

本文示例统一使用下面这张employees表:

id name email department salary
1 JohnSmith john.smith@example.com IT 65000
2 EmmaJohnson emma.johnson@example.com HR 55000
3 MichaelBrown michael.brown@example.com Finance 70000
4 SophiaDavis sophia.davis@example.com Marketing 60000

删除单条记录

按主键删除是最常见也安全的场景,因为id唯一,最多只会命中一行。

const mysql = require('mysql2');

const connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: 'your_password',
  database: 'companydb'
});

const sql = "DELETE FROM employees WHERE id = 2";

connection.query(sql, (err, result) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log("员工记录已删除");
});

connection.end();

connection.query()把SQL发给MySQL执行,回调里的err为null就说明语句本身没报错。注意这里只代表“语句执行成功”,不代表“确实删掉了一行”,后面会讲怎么判断。

删除多条记录

WHERE条件不局限于主键,任何能匹配多行的条件都可以。

const sql = "DELETE FROM employees WHERE department = 'Marketing'";

connection.query(sql, (err, result) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log("市场部员工记录已删除");
});

只要department等于Marketing的行都会被删掉。这类批量删除在执行前一定要先用SELECT确认影响范围,尤其是条件字段没有索引或者取值比较宽泛的时候。

用参数化查询处理用户输入

把用户传来的值直接拼进SQL字符串是典型的安全隐患。假设前端传过来一个id,你写成:

const sql = `DELETE FROM employees WHERE id = ${employeeId}`;

如果employeeId被构造成1OR1=1,整张表就被清空了。正确做法是用?占位符,把值作为数组单独传给query方法:

const employeeId = 3;

const sql = "DELETE FROM employees WHERE id = ?";

connection.query(sql, [employeeId], (err, result) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log("员工记录已删除");
});

mysql2会自动把占位符替换成经过转义的值,字符串会加引号,数字按数字处理,注入的构造串会失去作用。这是mysql2相比自己拼字符串最实际的价值。

多个占位符就按顺序传多个值:

const sql = "DELETE FROM employees WHERE department = ? AND salary < ?";
connection.query(sql, ['IT', 60000], callback);

用affectedRows判断实际删了几行

result.affectedRows表示这条DELETE真正影响的行数。这是判断删除结果最直接的依据。

const sql = "DELETE FROM employees WHERE department = 'HR'";

connection.query(sql, (err, result) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log("受影响行数:", result.affectedRows);
});

affectedRows为1说明删掉了一行,为0说明没有任何行匹配条件。很多接口的bug就出在这里:只判断err是否为null,然后返回“删除成功”,但用户删的id根本不存在,affectedRows是0,数据一条没动。前端拿到“成功”提示,刷新一看记录还在。

删完之后验证一下

删除是写操作,想确认结果是否生效,用SELECT查一次最直观。

const sql = "SELECT * FROM employees WHERE id = 2";

connection.query(sql, (err, results) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log(results);
});

如果输出是空数组[],说明id为2的记录已经不在了。这个小动作在调试删除逻辑时很有用,比反复看日志快。

清空整张表但不删表结构

不写WHERE就是删除所有行:

const sql = "DELETE FROM employees";

connection.query(sql, (err, result) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log("全部员工记录已删除");
  console.log("受影响行数:", result.affectedRows);
});

执行后表结构、列、索引、约束都保留,只是数据清空。如果确实需要清空全表,MySQL里还有TRUNCATETABLE,它比不带WHERE的DELETE更快,因为不走逐行删除和事务日志,但TRUNCATE不能带条件,也不能回滚,用之前要清楚区别。

错误处理:表名写错这类问题怎么暴露

const sql = "DELETE FROM employee WHERE id = 1";

connection.query(sql, (err, result) => {
  if (err) {
    console.error("错误:", err.message);
    return;
  }
  console.log("员工记录已删除");
});

实际表名是employees,这里写成了employee,MySQL会返回:

Error: Table 'companydb.employee' doesn't exist

err.message把原因说得很清楚。数据库连接失败、权限不足、外键约束阻止删除,也都会通过err传回来。回调风格里必须显式判断err并return,否则后续代码会拿着undefined的result继续跑。

完整示例:连接、删除、判断结果、关闭连接

const mysql = require('mysql2');

const connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: 'your_password',
  database: 'companydb'
});

const employeeId = 4;
const sql = "DELETE FROM employees WHERE id = ?";

connection.query(sql, [employeeId], (err, result) => {
  if (err) {
    console.error("错误:", err.message);
    return;
  }

  if (result.affectedRows > 0) {
    console.log("员工记录已删除");
  } else {
    console.log("未找到对应员工");
  }

  console.log("受影响行数:", result.affectedRows);
});

connection.end();

这段代码把前面几个要点串起来了:mysql2引入、连接建立、参数化查询、affectedRows判断、连接关闭。affectedRows大于0才提示删除成功,等于0就明确告诉调用方没找到记录,避免误报。

现在写法:Promise与async/await

回调风格在稍大的项目里容易形成嵌套。mysql2提供了promise版本,配合async/await写起来更线性,错误处理也能用try/catch统一收口。

const mysql = require('mysql2/promise');

async function deleteEmployee(employeeId) {
  const connection = await mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: 'your_password',
    database: 'companydb'
  });

  try {
    const sql = "DELETE FROM employees WHERE id = ?";
    const [result] = await connection.execute(sql, [employeeId]);

    if (result.affectedRows === 0) {
      return { success: false, message: "未找到对应员工" };
    }
    return { success: true, affectedRows: result.affectedRows };
  } catch (err) {
    console.error("删除失败:", err.message);
    throw err;
  } finally {
    await connection.end();
  }
}

这里用的是connection.execute(),它和query都能执行参数化语句,execute走的是预处理语句路径,在需要反复执行同类语句时更合适。finally里关闭连接,保证异常情况下连接也能释放。

本节课程知识要点

  • DELETE删除的是行记录,DROPTABLE删除的是整张表,两者不可混用

  • 不写WHERE会清空全表,执行前先用SELECT验证条件范围

  • 用户输入一律走?占位符,不要拼接字符串

  • 用result.affectedRows判断实际删除行数,不能只看err是否为null

  • 表名、字段名拼写错误会通过err.message暴露,回调里必须判断并return

  • 大批量删除或线上操作前做好备份,删除不可逆

  • mysql2/promise配合async/await更适合现在项目结构

练习思考题

  1. 写一条DELETE语句,删除employees表中salary低于60000且department为IT的记录,并用affectedRows输出删了几行。

  2. 把上面的回调写法改写成mysql2/promise+async/await版本,要求删除失败时抛出异常,删除0行时返回明确提示。

  3. 如果一张表被另一张表通过外键引用,直接DELETE被引用的行会发生什么?如何在不破坏数据完整性的前提下处理?

  4. 不使用WHERE的DELETE和TRUNCATETABLE都能清空表,说说各自适用的场景和限制。

← MySQL 更新数据 MySQL 读取数据 →
分享笔记 (共有 篇笔记)
验证码:
微信公众号