← 创建 MySQL MySQL 插入数据 →

Node.js操作MySQL创建数据表:从连接配置到建表实践

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

为什么要在Node.js中建表

把建表动作放在Node.js里执行,不是为了替代数据库管理工具,而是为了解决几个实际场景:项目初始化时需要自动准备表结构、多环境部署时要保证开发库和测试库结构一致、CI流程中需要脚本化地重建测试表。MySQL Workbench适合人工设计和调整,Node.js脚本适合纳入版本控制和自动化流程。两者定位不同,不存在谁替代谁的问题。

本文围绕mysql这个Node.js驱动包展开。需要注意,mysql包目前处于维护状态,mysql2是更活跃的替代方案,API高度兼容且支持Promise。本文以mysql包为主线讲解,在末尾会说明mysql2的惯用写法,便于你根据项目情况选择。

环境准备与项目初始化

开始之前需要确认本机已安装Node.js、MySQLServer,并准备一个代码编辑器。JavaScript和SQL的基础语法需要熟悉,否则后续排查错误会比较吃力。

新建项目目录并初始化:

mkdir node-mysql-demo
cd node-mysql-demo
npm init -y

npminit-y会生成package.json,省去交互式填写。接着安装mysql包:

npm install mysql

安装完成后,package.json的dependencies中会出现mysql条目。这一步的意义在于把驱动依赖固化到项目配置中,换一台机器执行npminstall就能还原环境,而不是靠记忆手动装包。

准备目标数据库

建表之前必须先有数据库。用MySQL命令行或Workbench执行:

CREATE DATABASE employeedb;
USE employeedb;

这里没有用CREATEDATABASEIF NOT EXISTS,是因为数据库通常只创建一次,重复执行报错反而能提醒你当前连接到了哪个实例。建表语句则不同,后面会专门讲IF NOT EXISTS的用法。

建立Node.js与MySQL的连接

在项目根目录新建app.js,写入连接代码:

const mysql = require('mysql');

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

connection.connect((err) => {
    if (err) {
        console.error('Connection failed:', err.message);
        return;
    }
    console.log('Connected to MySQL database!');
});

几个参数的含义需要说清楚。host指向MySQL服务地址,本地开发一般是localhost;user和password是数据库账号凭据,password必须替换成真实密码,直接写明文在生产环境不可取,后面会给出改进方向;database指定默认操作的库,省去每次查询都写库名。

connection.connect()的回调里先判断err,这是Node.js回调风格的基本习惯。出错时打印err.message而不是整个err对象,输出更干净,定位问题也更直接。

建表语句的设计

employees表的结构如下:

CREATE TABLE employees (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100),
    age INT,
    email VARCHAR(100)
);

id设为INT主键并加AUTO_INCREMENT,插入数据时不需要手动指定,MySQL会自动递增。name和email用VARCHAR(100),100是字符长度上限,对姓名和常规邮箱足够。age用INT,不需要小数。

这里有个经验点:email字段如果业务上要求唯一,应该加UNIQUE约束,而不是靠应用层查重。数据库层约束才是之后一道防线,应用层判断存在并发漏洞。本文为保持示例简洁未加,实际项目中建议补上。

在Node.js中执行建表

把建表语句放进连接回调中执行:

const mysql = require('mysql');

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

connection.connect((err) => {
    if (err) {
        console.error('Connection failed:', err.message);
        return;
    }

    console.log('Connected to MySQL database!');

    const sql = `
        CREATE TABLE employees (
            id INT PRIMARY KEY AUTO_INCREMENT,
            name VARCHAR(100),
            age INT,
            email VARCHAR(100)
        )
    `;

    connection.query(sql, (err, result) => {
        if (err) {
            console.error('Error creating table:', err.message);
            connection.end();
            return;
        }

        console.log('employees table created successfully!');
        connection.end();
    });
});

connection.query()负责发送SQL并接收结果。回调中的err和result分别对应失败和成功两种情况。无论成功失败,都调用了connection.end()关闭连接。这一点容易被忽略:脚本执行完不关连接,Node.js进程可能挂起不退出,在定时任务或批处理脚本中会造成资源浪费。

运行nodeapp.js,正常输出为:

Connected to MySQL database!
employees table created successfully!

验证表是否创建成功

在MySQL客户端执行:

SHOW TABLES;

可以看到employees。再用DESCRIBE查看结构:

DESCRIBE employees;

返回的Field、Type、Key三列分别对应字段名、数据类型和键类型,id行的Key显示为PRI,说明主键生效。养成建表后验证的习惯,比等到插入数据报错再回头查要省事。

重复建表的处理:IF NOT EXISTS

第二次执行同样的CREATETABLE会直接报错,提示表已存在。在自动化脚本中这通常不是想要的结果。改用:

CREATE TABLE IF NOT EXISTS employees (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100),
    age INT,
    email VARCHAR(100)
);

Node.js中写法一致:

const sql = `
    CREATE TABLE IF NOT EXISTS employees (
        id INT PRIMARY KEY AUTO_INCREMENT,
        name VARCHAR(100),
        age INT,
        email VARCHAR(100)
    )
`;

connection.query(sql, (err, result) => {
    if (err) {
        console.error('Error:', err.message);
        return;
    }
    console.log('Table is ready!');
});

IF NOT EXISTS的语义是:表不存在就建,存在就跳过,不报错。适合初始化脚本反复执行的场景。但要注意它只判断表名,不判断结构。如果表已存在但字段和你的预期不一致,它不会做任何修改,也不会提示。结构变更仍需ALTERTABLE或迁移工具处理。

常见错误与排查方向

错误信息 可能原因
Accessdeniedforuser 用户名或密码错误
Unknowndatabase 指定的数据库不存在
Tablealreadyexists 同名表已存在,未加IF NOT EXISTS
ECONNREFUSED MySQL服务未启动或地址不可达
SQLsyntaxerror CREATETABLE语句语法有误

err.message是排查的第一手信息,先看它再决定下一步。凭据问题去核对配置,连接问题去检查服务状态,语法问题去比对SQL写法。

项目中的几点反思

第一,密码不要硬编码。开发阶段图方便可以写在代码里,但只要代码进版本库,凭据就泄露了。用环境变量读取是成本较低的改进:

require('dotenv').config();

const connection = mysql.createConnection({
    host: process.env.DB_HOST,
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    database: process.env.DB_NAME
});

第二,连接用完要关闭。单次脚本用connection.end(),Web服务中则不应该每次请求都建连接,而要用连接池mysql.createPool()。连接池复用连接,避免频繁握手开销,这是生产环境的常规做法。

第三,建表逻辑和业务逻辑分开。把建表语句单独放在migration目录或初始化脚本中,不要混在业务代码里。表结构变更应该有迹可循,而不是散落在各处。

mysql2的惯用写法

如果项目使用mysql2,建表代码可以写成Promise风格:

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

async function createTable() {
    const connection = await mysql.createConnection({
        host: 'localhost',
        user: 'root',
        password: process.env.DB_PASSWORD,
        database: 'employeedb'
    });

    try {
        await connection.query(`
            CREATE TABLE IF NOT EXISTS employees (
                id INT PRIMARY KEY AUTO_INCREMENT,
                name VARCHAR(100),
                age INT,
                email VARCHAR(100)
            )
        `);
        console.log('Table is ready!');
    } catch (err) {
        console.error('Error:', err.message);
    } finally {
        await connection.end();
    }
}

createTable();

async/await让错误处理用try/catch/finally表达,比嵌套回调更清晰。mysql2同时支持回调和Promise,迁移成本低,新项目可以优先考虑。

本节课程知识要点

  • mysql包通过createConnection建立连接,query方法执行SQL

  • CREATETABLE定义字段名、数据类型和约束,PRIMARYKEY与AUTO_INCREMENT常配合使用

  • IF NOT EXISTS避免重复建表报错,但不负责结构变更

  • 连接使用后需end()关闭,Web场景应改用连接池

  • 凭据通过环境变量管理,不硬编码进代码库

  • mysql2提供Promise接口,写法更贴近现在Node.js

练习与思考

  1. 在employees表的email字段上添加UNIQUE约束,写出完整的CREATETABLE语句。

  2. 用mysql2改写本文的建表脚本,改为async/await风格。

  3. 思考:如果表已存在但需要新增一个department字段,IF NOT EXISTS能否满足需求?应该用什么语句?

  4. 尝试用连接池替换单连接,观察代码结构需要做哪些调整。

Node.js建表本身不复杂,难点在于把连接管理、错误处理、凭据安全和结构变更这几件事放到项目整体中考虑。示例代码能跑通只是起点,真正决定代码质量的是对边界情况的处理。建议从本文示例出发,逐步替换成mysql2和环境变量配置,把建表脚本纳入项目的初始化流程,而不是每次手动执行。

← 创建 MySQL MySQL 插入数据 →
分享笔记 (共有 篇笔记)
验证码:
微信公众号