‌Node.js数据库操作指南‌

目录

  1. 前言
  2. 环境配置与通用准备
  3. Node.js 与 MySQL

  4. Node.js 与 PostgreSQL

  5. Node.js 与 MongoDB

  6. 使用 ORM:Sequelize 示例

  7. 使用 ORM:TypeORM 示例

  8. 常见问题与性能调优
  9. 总结

前言

数据库操作是后端应用的核心组成部分。在 Node.js 生态中,无论是使用原生驱动(如 mysql2pgmongodb),还是借助 ORM(Sequelize、TypeORM 等),都能高效地完成数据持久化操作。本指南将带你系统了解:

  • 如何在 Node.js 中安装、配置并连接常见关系型与 NoSQL 数据库
  • 各类 CRUD 操作示例,并通过代码与图解帮助理解底层流程
  • 连接池与事务的使用,以及性能优化思路
  • ORM 框架(Sequelize、TypeORM)如何简化工作,并演示常见模型与关联操作

环境配置与通用准备

  1. Node.js 版本:建议 v14 或以上(支持 async/await)。
  2. 包管理器:npm 或 yarn,以下示例均使用 npm。
  3. 数据库服务:本地或远程安装 MySQL、PostgreSQL、MongoDB。示例中假设本地数据库已启动并可连接。

打开终端,先初始化一个 Node.js 项目:

mkdir node-db-guide
cd node-db-guide
npm init -y

安装一些通用依赖(须根据后续示例逐个安装):

npm install dotenv
npm install --save-dev nodemon
  • dotenv:用于加载 .env 环境变量文件,统一管理数据库连接信息等配置。
  • nodemon:开发阶段热重启脚本。

在项目根目录创建接口:.env,并填入示例数据库连接配置(请根据实际情况修改):

# .env 示例
MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_USER=root
MYSQL_PASSWORD=123456
MYSQL_DATABASE=test_db

PG_HOST=localhost
PG_PORT=5432
PG_USER=postgres
PG_PASSWORD=123456
PG_DATABASE=test_db

MONGO_URI=mongodb://localhost:27017/test_db

在项目根目录新建 config.js,统一读取环境变量:

// config.js
require('dotenv').config();

module.exports = {
  mysql: {
    host: process.env.MYSQL_HOST,
    port: process.env.MYSQL_PORT,
    user: process.env.MYSQL_USER,
    password: process.env.MYSQL_PASSWORD,
    database: process.env.MYSQL_DATABASE
  },
  pg: {
    host: process.env.PG_HOST,
    port: process.env.PG_PORT,
    user: process.env.PG_USER,
    password: process.env.PG_PASSWORD,
    database: process.env.PG_DATABASE
  },
  mongoUri: process.env.MONGO_URI
};

Node.js 与 MySQL

3.1 安装与连接

推荐使用 mysql2 驱动,支持 Promise API。

npm install mysql2

代码示例:mysql-connection.js

// mysql-connection.js
const mysql = require('mysql2/promise');
const config = require('./config');

async function testMySQL() {
  // 1. 创建连接
  const connection = await mysql.createConnection({
    host: config.mysql.host,
    port: config.mysql.port,
    user: config.mysql.user,
    password: config.mysql.password,
    database: config.mysql.database
  });

  console.log('已连接到 MySQL');

  // 2. 执行简单查询
  const [rows] = await connection.query('SELECT NOW() AS now;');
  console.log('当前时间:', rows[0].now);

  // 3. 关闭连接
  await connection.end();
  console.log('连接已关闭');
}

testMySQL().catch(console.error);

运行:

node mysql-connection.js

输出示意:

已连接到 MySQL
当前时间: 2023-08-10T12:34:56.000Z
连接已关闭

图解:MySQL 连接流程

┌──────────────┐        ┌───────────┐
│ Node.js 应用 │──发送连接请求──▶│ MySQL 服务 │
└──────────────┘        └───────────┘
       ▲                        │
       │   连接成功/失败        │
       │◀───────────────────────┘

3.2 增删改查示例

假设已有一个名为 users 的表:

CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  username VARCHAR(50) NOT NULL,
  email VARCHAR(100) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

示例代码:mysql-crud.js

// mysql-crud.js
const mysql = require('mysql2/promise');
const config = require('./config');

async function runCRUD() {
  const conn = await mysql.createConnection(config.mysql);

  // 插入(Create)
  const [insertResult] = await conn.execute(
    'INSERT INTO users (username, email) VALUES (?, ?)',
    ['alice', 'alice@example.com']
  );
  console.log('插入用户 ID:', insertResult.insertId);

  // 查询(Read)
  const [rows] = await conn.execute('SELECT * FROM users WHERE id = ?', [
    insertResult.insertId
  ]);
  console.log('查询结果:', rows);

  // 更新(Update)
  const [updateResult] = await conn.execute(
    'UPDATE users SET email = ? WHERE id = ?',
    ['alice_new@example.com', insertResult.insertId]
  );
  console.log('更新受影响行数:', updateResult.affectedRows);

  // 删除(Delete)
  const [deleteResult] = await conn.execute(
    'DELETE FROM users WHERE id = ?',
    [insertResult.insertId]
  );
  console.log('删除受影响行数:', deleteResult.affectedRows);

  await conn.end();
}

runCRUD().catch(console.error);

执行与输出示意:

node mysql-crud.js
插入用户 ID: 1
查询结果: [ { id: 1, username: 'alice', email: 'alice@example.com', created_at: 2023-08-10T12:45:00.000Z } ]
更新受影响行数: 1
删除受影响行数: 1

3.3 连接池与性能优化

单次连接在高并发场景中非常 inefficient,推荐使用连接池。

示例代码:mysql-pool.js

// mysql-pool.js
const mysql = require('mysql2/promise');
const config = require('./config');

const pool = mysql.createPool({
  host: config.mysql.host,
  port: config.mysql.port,
  user: config.mysql.user,
  password: config.mysql.password,
  database: config.mysql.database,
  waitForConnections: true,
  connectionLimit: 10, // 最大连接数
  queueLimit: 0
});

async function queryUsers() {
  // 从连接池获取连接
  const conn = await pool.getConnection();
  try {
    const [rows] = await conn.query('SELECT * FROM users');
    console.log('所有用户:', rows);
  } finally {
    conn.release(); // 归还连接到池中
  }
}

async function main() {
  await queryUsers();
  // 程序结束时可以调用 pool.end() 关闭所有连接
  await pool.end();
}

main().catch(console.error);

连接池流程图(ASCII)

┌──────────────┐
│ Node.js 应用 │
└──────────────┘
       │
       ▼
┌─────────────────┐
│ 连接池 (Pool)    │
│ ┌─────────────┐ │
│ │ Connection1 │ │
│ │ Connection2 │ │
│ │   ...       │ │
│ └─────────────┘ │
└─────────────────┘
       ▲
       │
   多个并发请求

好处:

  • 减少频繁创建/关闭连接的开销
  • 复用空闲连接,提升并发吞吐
  • 可通过 connectionLimit 控制最大并发连接数,防止数据库过载

3.4 事务示例

事务用于保证一系列 SQL 操作要么全部成功,要么全部回滚,常用于银行转账等场景。

示例代码:mysql-transaction.js

// mysql-transaction.js
const mysql = require('mysql2/promise');
const config = require('./config');

async function transferFunds(fromUserId, toUserId, amount) {
  const conn = await mysql.createConnection(config.mysql);

  try {
    // 开启事务
    await conn.beginTransaction();

    // 扣减转出方余额
    const [res1] = await conn.execute(
      'UPDATE accounts SET balance = balance - ? WHERE user_id = ?',
      [amount, fromUserId]
    );
    if (res1.affectedRows !== 1) throw new Error('扣款失败');

    // 增加转入方余额
    const [res2] = await conn.execute(
      'UPDATE accounts SET balance = balance + ? WHERE user_id = ?',
      [amount, toUserId]
    );
    if (res2.affectedRows !== 1) throw new Error('收款失败');

    // 提交事务
    await conn.commit();
    console.log('转账成功');
  } catch (err) {
    // 回滚事务
    await conn.rollback();
    console.error('转账失败,已回滚:', err.message);
  } finally {
    await conn.end();
  }
}

transferFunds(1, 2, 100).catch(console.error);

事务流程图(ASCII)

┌────────────────────────────────┐
│   conn.beginTransaction()     │
└─────────────┬──────────────────┘
              │
   ┌──────────▼──────────┐
   │ UPDATE accounts ... │
   │  res1                │
   └──────────┬──────────┘
              │
   ┌──────────▼──────────┐
   │ UPDATE accounts ... │
   │  res2                │
   └──────────┬──────────┘
              │
   ┌──────────▼──────────┐
   │   conn.commit()     │
   └─────────────────────┘

 (若任一步失败,则执行 conn.rollback())

Node.js 与 PostgreSQL

4.1 安装与连接

使用 pg 驱动,支持 Pool 与事务。

npm install pg

示例代码:pg-connection.js

// pg-connection.js
const { Client } = require('pg');
const config = require('./config');

async function testPG() {
  const client = new Client({
    host: config.pg.host,
    port: config.pg.port,
    user: config.pg.user,
    password: config.pg.password,
    database: config.pg.database
  });
  await client.connect();
  console.log('已连接到 PostgreSQL');

  const res = await client.query('SELECT NOW() AS now;');
  console.log('当前时间:', res.rows[0].now);

  await client.end();
  console.log('连接已关闭');
}

testPG().catch(console.error);

运行:

node pg-connection.js

4.2 增删改查示例

假设有一个 products 表:

CREATE TABLE products (
  id SERIAL PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  price NUMERIC NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

示例代码:pg-crud.js

// pg-crud.js
const { Pool } = require('pg');
const config = require('./config');

const pool = new Pool({
  host: config.pg.host,
  port: config.pg.port,
  user: config.pg.user,
  password: config.pg.password,
  database: config.pg.database,
  max: 10
});

async function runCRUD() {
  // 插入
  const insertRes = await pool.query(
    'INSERT INTO products (name, price) VALUES ($1, $2) RETURNING id',
    ['Apple', 3.5]
  );
  const productId = insertRes.rows[0].id;
  console.log('插入产品 ID:', productId);

  // 查询
  const selectRes = await pool.query('SELECT * FROM products WHERE id = $1', [
    productId
  ]);
  console.log('查询结果:', selectRes.rows);

  // 更新
  const updateRes = await pool.query(
    'UPDATE products SET price = $1 WHERE id = $2',
    [4.0, productId]
  );
  console.log('更新受影响行数:', updateRes.rowCount);

  // 删除
  const deleteRes = await pool.query('DELETE FROM products WHERE id = $1', [
    productId
  ]);
  console.log('删除受影响行数:', deleteRes.rowCount);

  await pool.end();
}

runCRUD().catch(console.error);

4.3 事务示例

示例代码:pg-transaction.js

// pg-transaction.js
const { Pool } = require('pg');
const config = require('./config');

const pool = new Pool({
  host: config.pg.host,
  port: config.pg.port,
  user: config.pg.user,
  password: config.pg.password,
  database: config.pg.database,
  max: 10
});

async function transferFunds(fromId, toId, amount) {
  const client = await pool.connect();
  try {
    await client.query('BEGIN');

    const res1 = await client.query(
      'UPDATE accounts SET balance = balance - $1 WHERE user_id = $2',
      [amount, fromId]
    );
    if (res1.rowCount !== 1) throw new Error('扣款失败');

    const res2 = await client.query(
      'UPDATE accounts SET balance = balance + $1 WHERE user_id = $2',
      [amount, toId]
    );
    if (res2.rowCount !== 1) throw new Error('收款失败');

    await client.query('COMMIT');
    console.log('转账成功');
  } catch (err) {
    await client.query('ROLLBACK');
    console.error('转账失败,已回滚:', err.message);
  } finally {
    client.release();
  }
}

transferFunds(1, 2, 50).catch(console.error);

Node.js 与 MongoDB

5.1 安装与连接

使用官方驱动 mongodb 或 ODM mongoose。下面优先介绍 mongodb 官方驱动。

npm install mongodb

示例代码:mongo-connection.js

// mongo-connection.js
const { MongoClient } = require('mongodb');
const config = require('./config');

async function testMongo() {
  const client = new MongoClient(config.mongoUri, {
    useNewUrlParser: true,
    useUnifiedTopology: true
  });
  await client.connect();
  console.log('已连接到 MongoDB');

  const db = client.db(); // 默认 test_db
  const coll = db.collection('test_collection');

  // 插入文档
  const insertRes = await coll.insertOne({ name: 'Bob', age: 28 });
  console.log('插入文档 ID:', insertRes.insertedId);

  // 查询文档
  const doc = await coll.findOne({ _id: insertRes.insertedId });
  console.log('查询文档:', doc);

  await client.close();
}

testMongo().catch(console.error);

5.2 增删改查示例

假设使用 users 集合:

示例代码:mongo-crud.js

// mongo-crud.js
const { MongoClient, ObjectId } = require('mongodb');
const config = require('./config');

async function runCRUD() {
  const client = new MongoClient(config.mongoUri, {
    useNewUrlParser: true,
    useUnifiedTopology: true
  });
  await client.connect();
  const db = client.db();
  const users = db.collection('users');

  // 插入
  const { insertedId } = await users.insertOne({
    username: 'charlie',
    email: 'charlie@example.com',
    createdAt: new Date()
  });
  console.log('插入文档 ID:', insertedId);

  // 查询
  const user = await users.findOne({ _id: insertedId });
  console.log('查询结果:', user);

  // 更新
  const updateRes = await users.updateOne(
    { _id: insertedId },
    { $set: { email: 'charlie_new@example.com' } }
  );
  console.log('更新受影响文档数:', updateRes.modifiedCount);

  // 删除
  const deleteRes = await users.deleteOne({ _id: insertedId });
  console.log('删除受影响文档数:', deleteRes.deletedCount);

  await client.close();
}

runCRUD().catch(console.error);

5.3 常见索引与查询优化

在 MongoDB 中,为了让查询更高效,往往需要在常用筛选字段上创建索引。

示例:创建索引

// mongo-index.js
const { MongoClient } = require('mongodb');
const config = require('./config');

async function createIndex() {
  const client = new MongoClient(config.mongoUri, {
    useNewUrlParser: true,
    useUnifiedTopology: true
  });
  await client.connect();
  const db = client.db();
  const users = db.collection('users');

  // 在 username 字段上创建唯一索引
  await users.createIndex({ username: 1 }, { unique: true });
  console.log('已在 username 字段创建唯一索引');

  await client.close();
}

createIndex().catch(console.error);

查询优化思路

  • 索引覆盖:只返回索引字段,无需回表。
  • 分页查询:避免使用 skip 在大数据量时性能下降,推荐基于索引值做范围查询。
  • 聚合管道:使用 $match$project$group 等聚合操作,以减少传输数据量并利用索引。

使用 ORM:Sequelize 示例

Sequelize 是 Node.js 中较为流行的 ORM,可同时支持 MySQL、PostgreSQL、SQLite 等。

6.1 安装与配置

npm install sequelize mysql2

示例代码:sequelize-setup.js

// sequelize-setup.js
const { Sequelize, DataTypes } = require('sequelize');
const config = require('./config');

const sequelize = new Sequelize(
  config.mysql.database,
  config.mysql.user,
  config.mysql.password,
  {
    host: config.mysql.host,
    port: config.mysql.port,
    dialect: 'mysql',
    logging: false
  }
);

async function testSequelize() {
  try {
    await sequelize.authenticate();
    console.log('Sequelize 已连接到数据库');

    // 定义模型
    const User = sequelize.define('User', {
      id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
      username: { type: DataTypes.STRING(50), allowNull: false, unique: true },
      email: { type: DataTypes.STRING(100), allowNull: false }
    }, {
      tableName: 'users',
      timestamps: true, // 自动添加 createdAt 和 updatedAt
      underscored: true // 字段名使用下划线风格
    });

    // 同步模型(如果表不存在则创建)
    await User.sync({ alter: true });
    console.log('User 模型已同步');

    // 创建记录
    const user = await User.create({ username: 'david', email: 'david@example.com' });
    console.log('创建用户:', user.toJSON());

    // 查询
    const users = await User.findAll();
    console.log('所有用户:', users.map(u => u.toJSON()));

    // 更新
    await User.update({ email: 'david_new@example.com' }, { where: { id: user.id } });
    console.log('已更新用户 email');

    // 删除
    await User.destroy({ where: { id: user.id } });
    console.log('已删除用户');
  } catch (err) {
    console.error('Sequelize 操作失败:', err);
  } finally {
    await sequelize.close();
  }
}

testSequelize();

6.2 定义模型与同步

在实际项目中,一般会将模型定义与 Sequelize 实例分开,方便维护。推荐目录结构:

models/
  index.js        # Sequelize 实例与初始化
  user.js         # User 模型定义
app.js            # 应用主入口

models/index.js

const { Sequelize } = require('sequelize');
const config = require('../config');

const sequelize = new Sequelize(
  config.mysql.database,
  config.mysql.user,
  config.mysql.password,
  {
    host: config.mysql.host,
    port: config.mysql.port,
    dialect: 'mysql',
    logging: false
  }
);

const db = {};
db.sequelize = sequelize;
db.Sequelize = Sequelize;

// 导入模型
db.User = require('./user')(sequelize, Sequelize);

module.exports = db;

models/user.js

module.exports = (sequelize, DataTypes) => {
  const User = sequelize.define('User', {
    id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
    username: { type: DataTypes.STRING(50), allowNull: false, unique: true },
    email: { type: DataTypes.STRING(100), allowNull: false }
  }, {
    tableName: 'users',
    timestamps: true,
    underscored: true
  });
  return User;
};

app.js

// app.js
const db = require('./models');

async function main() {
  try {
    await db.sequelize.authenticate();
    console.log('已连接到数据库 (Sequelize)');

    // 同步所有模型
    await db.sequelize.sync({ alter: true });
    console.log('模型同步完成');

    // 创建用户示例
    const newUser = await db.User.create({ username: 'eve', email: 'eve@example.com' });
    console.log('创建用户:', newUser.toJSON());
  } catch (err) {
    console.error(err);
  } finally {
    await db.sequelize.close();
  }
}

main();

6.3 增删改查示例

在 Sequelize 中,常用方法包括:

  • Model.create():插入单条记录
  • Model.findAll({ where: {...} }):查询多条
  • Model.findOne({ where: {...} }):查询单条
  • Model.update({ fields }, { where: {...} }):更新
  • Model.destroy({ where: {...} }):删除

示例已在上节中演示,读者可在控制台运行并观察效果。


6.4 关联关系与事务

关联关系示例

假设有两个模型:UserPost,一对多关系,一个用户可有多篇文章。

定义模型:models/post.js

module.exports = (sequelize, DataTypes) => {
  const Post = sequelize.define('Post', {
    id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
    title: { type: DataTypes.STRING(200), allowNull: false },
    content: { type: DataTypes.TEXT, allowNull: false },
    userId: { type: DataTypes.INTEGER, allowNull: false }
  }, {
    tableName: 'posts',
    timestamps: true,
    underscored: true
  });
  return Post;
};

models/index.js 中配置关联:

const db = {};
db.sequelize = sequelize;
db.Sequelize = Sequelize;

db.User = require('./user')(sequelize, Sequelize);
db.Post = require('./post')(sequelize, Sequelize);

// 定义关联
db.User.hasMany(db.Post, { foreignKey: 'userId', as: 'posts' });
db.Post.belongsTo(db.User, { foreignKey: 'userId', as: 'author' });

module.exports = db;

使用关联:

// association-example.js
const db = require('./models');

async function associationDemo() {
  await db.sequelize.sync({ alter: true });

  // 创建用户与文章
  const user = await db.User.create({ username: 'frank', email: 'frank@example.com' });
  await db.Post.create({ title: 'Hello World', content: 'This is first post.', userId: user.id });

  // 查询用户并包含文章
  const result = await db.User.findOne({
    where: { id: user.id },
    include: [{ model: db.Post, as: 'posts' }]
  });
  console.log('用户与其文章:', JSON.stringify(result, null, 2));

  await db.sequelize.close();
}

associationDemo().catch(console.error);

事务示例

// sequelize-transaction.js
const db = require('./models');

async function transactionDemo() {
  const t = await db.sequelize.transaction();
  try {
    const user = await db.User.create({ username: 'grace', email: 'grace@example.com' }, { transaction: t });
    await db.Post.create({ title: 'Transaction Post', content: 'Using transaction', userId: user.id }, { transaction: t });
    // 提交
    await t.commit();
    console.log('事务提交成功');
  } catch (err) {
    await t.rollback();
    console.error('事务回滚:', err);
  } finally {
    await db.sequelize.close();
  }
}

transactionDemo().catch(console.error);

使用 ORM:TypeORM 示例

TypeORM 是另一个流行的 ORM,尤其在 TypeScript 项目中表现优异。这里以 JavaScript(可扩展到 TS)示例。

7.1 安装与配置

npm install typeorm reflect-metadata mysql2

tsconfig.json 中需要启用实验性装饰器和元数据:

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "target": "ES2019",
    "module": "commonjs",
    "outDir": "dist",
    "rootDir": "src"
    // …其他选项
  }
}

示例目录:

src/
  entity/
    User.js
  index.js
  ormconfig.json

ormconfig.json

{
  "type": "mysql",
  "host": "localhost",
  "port": 3306,
  "username": "root",
  "password": "123456",
  "database": "test_db",
  "synchronize": true,
  "logging": false,
  "entities": ["src/entity/**/*.js"]
}

7.2 定义实体与数据库同步

示例实体:src/entity/User.js

// src/entity/User.js
const { EntitySchema } = require('typeorm');

module.exports = new EntitySchema({
  name: 'User',
  tableName: 'users',
  columns: {
    id: {
      type: 'int',
      primary: true,
      generated: true
    },
    username: {
      type: 'varchar',
      length: 50,
      unique: true
    },
    email: {
      type: 'varchar',
      length: 100
    },
    createdAt: {
      type: 'timestamp',
      createDate: true
    },
    updatedAt: {
      type: 'timestamp',
      updateDate: true
    }
  }
});

src/index.js

// src/index.js
require('reflect-metadata');
const { createConnection, getRepository } = require('typeorm');

async function main() {
  const connection = await createConnection();
  console.log('已连接到数据库 (TypeORM)');

  const userRepo = getRepository('User');

  // 插入
  const user = userRepo.create({ username: 'hannah', email: 'hannah@example.com' });
  await userRepo.save(user);
  console.log('插入用户:', user);

  // 查询
  const users = await userRepo.find();
  console.log('所有用户:', users);

  // 更新
  user.email = 'hannah_new@example.com';
  await userRepo.save(user);
  console.log('更新用户:', user);

  // 删除
  await userRepo.delete(user.id);
  console.log('删除用户 ID:', user.id);

  await connection.close();
}

main().catch(console.error);

7.3 增删改查示例

在上节代码中,常用操作如下:

  • repo.create({ … }):生成实体实例
  • repo.save(entity):插入或更新(根据主键是否存在)
  • repo.find():查询所有记录
  • repo.findOne({ where: { … } }):条件查询单条
  • repo.delete(id):通过主键删除

7.4 关联关系示例

假设有 Post 实体与 User 实体,一对多关系:

src/entity/Post.js

const { EntitySchema } = require('typeorm');

module.exports = new EntitySchema({
  name: 'Post',
  tableName: 'posts',
  columns: {
    id: {
      type: 'int',
      primary: true,
      generated: true
    },
    title: {
      type: 'varchar',
      length: 200
    },
    content: {
      type: 'text'
    }
  },
  relations: {
    author: {
      type: 'many-to-one',
      target: 'User',
      joinColumn: { name: 'userId' },
      inverseSide: 'posts'
    }
  }
});

更新 src/entity/User.js 添加关联:

module.exports = new EntitySchema({
  name: 'User',
  tableName: 'users',
  columns: {
    id: { type: 'int', primary: true, generated: true },
    username: { type: 'varchar', length: 50, unique: true },
    email: { type: 'varchar', length: 100 },
    createdAt: { type: 'timestamp', createDate: true },
    updatedAt: { type: 'timestamp', updateDate: true }
  },
  relations: {
    posts: {
      type: 'one-to-many',
      target: 'Post',
      inverseSide: 'author'
    }
  }
});

更新 src/index.js 查询示例:

// src/index.js
require('reflect-metadata');
const { createConnection, getRepository } = require('typeorm');

async function main() {
  const connection = await createConnection();
  const userRepo = getRepository('User');
  const postRepo = getRepository('Post');

  // 创建用户
  const user = userRepo.create({ username: 'ivan', email: 'ivan@example.com' });
  await userRepo.save(user);

  // 创建文章
  const post = postRepo.create({
    title: 'TypeORM Guide',
    content: 'This is a post using TypeORM.',
    author: user
  });
  await postRepo.save(post);

  // 查询用户及其文章
  const result = await userRepo.findOne({
    where: { id: user.id },
    relations: ['posts']
  });
  console.log('用户及其文章:', JSON.stringify(result, null, 2));

  await connection.close();
}

main().catch(console.error);

常见问题与性能调优

  1. 连接超时或频繁断开

    • 使用连接池替代单次连接。
    • 在生产环境设置合理的 connectionLimit 或 pool 的 idleTimeout
  2. SQL 注入风险

    • 强烈建议使用参数化查询(?$1 语法),不要直接拼接字符串。
  3. OOM / 大结果集拉取

    • 对于大量数据,使用分页查询(LIMIT/OFFSET 或基于主键范围查询)。
    • Node.js 中对大结果集可使用流式查询(如 mysql2queryStream())。
  4. 事务死锁

    • 控制事务粒度,尽量在同一顺序访问表。
    • 避免在事务中做长时间操作(如外部 API 调用)。
  5. MongoDB 大数据查询性能

    • 创建合适的索引,避免全表扫描;
    • 使用聚合管道(aggregation pipeline)代替多次拉取。
  6. ORM 性能开销

    • ORM 便于开发,但对于极端性能场景,建议使用原生 SQL;
    • 在 Sequelize/TypeORM 中,尽量使用批量操作(bulkCreatesaveMany)减少网络往返。

总结

本文围绕 Node.js 与几种常见数据库(MySQL、PostgreSQL、MongoDB)以及两种主流 ORM 框架(Sequelize、TypeORM)进行了全面介绍:

  1. MySQL 驱动与连接池:包括基础 CRUD、连接池与事务示例。
  2. PostgreSQL 驱动示例:使用 pg 驱动完成类似操作。
  3. MongoDB 官方驱动:完成文档的插入、查询、更新、删除,并说明索引优化思路。
  4. Sequelize ORM:从安装、模型定义、增删改查到事务与关联操作全面举例。
  5. TypeORM 示例:同样展示创建连接、实体定义与关联映射。
  6. 性能与常见问题:给出连接超时、注入风险、大结果集处理与事务死锁等优化建议。

通过本文内容,您可以根据实际项目需求选择合适的数据库驱动或 ORM 工具,结合连接池与事务等技术,实现高效、可靠的数据库访问层。同时,图解与代码示例能够帮助您快速理解底层工作原理,并掌握常见坑点与优化思路。

最后修改于:2025年05月30日 11:31

评论已关闭

推荐阅读

DDPG 模型解析,附Pytorch完整代码
2024年11月24日
DQN 模型解析,附Pytorch完整代码
2024年11月24日
AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日