Cơ sở dữ liệu và Node.js

Dưới đây là phần giải thích đầy đủ và chuyên sâu theo góc nhìn của Senior Backend Developer về cách Node.js tương tác với cơ sở dữ liệu, sử dụng Mongoose, và quản lý kết nối hiệu quả:


1. Node.js tương tác với cơ sở dữ liệu như thế nào?

Node.js có thể kết nối với hầu hết các loại cơ sở dữ liệu thông qua drivers hoặc ORM/ODM, phổ biến nhất là:

🔹 Quan hệ (SQL): MySQL, PostgreSQL, MSSQL

  • Dùng các driver như: mysql2, pg, sequelize, typeorm.

🔹 Phi quan hệ (NoSQL): MongoDB, Redis

  • MongoDB: dùng mongoose, mongodb.

  • Redis: dùng ioredis, node-redis.

Ví dụ: MySQL

const mysql = require('mysql2');

const pool = mysql.createPool({
  host: 'localhost',
  user: 'root',
  database: 'test'
});

pool.query('SELECT * FROM users', (err, results) => {
  if (err) throw err;
  console.log(results);
});

Ví dụ: MongoDB (native)

const { MongoClient } = require('mongodb');

const client = new MongoClient('mongodb://localhost:27017');
await client.connect();
const db = client.db('test');
const users = await db.collection('users').find().toArray();

2. Mongoose là gì và cách sử dụng với MongoDB trong Node.js

🔹 Mongoose là gì?

Mongoose là một ODM (Object Data Modeling) cho MongoDB, giúp:

  • Định nghĩa schema rõ ràng.

  • Mapping giữa documents và JS objects.

  • Có tính năng middleware, validation, và query helpers.

Cách sử dụng Mongoose cơ bản:

1. Cài đặt

npm install mongoose

2. Kết nối MongoDB

const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/test', {
  useNewUrlParser: true,
  useUnifiedTopology: true
});

3. Định nghĩa Schema và Model

const userSchema = new mongoose.Schema({
  name: String,
  email: String,
  createdAt: { type: Date, default: Date.now }
});

const User = mongoose.model('User', userSchema);

4. CRUD Example

// Create
const user = await User.create({ name: 'Tài', email: 'tai@example.com' });

// Read
const users = await User.find();

// Update
await User.updateOne({ _id: user._id }, { name: 'Tài Titans' });

// Delete
await User.deleteOne({ _id: user._id });

3. Quản lý kết nối cơ sở dữ liệu trong Node.js để tránh rò rỉ bộ nhớ

🔹 Vấn đề thường gặp:

  • Kết nối bị mở nhưng không đóng.

  • Quá nhiều kết nối gây "connection pool exhaustion".

  • Reconnect logic sai khi server restart hoặc DB bị down.

Best Practices:

🔸 1. Dùng Connection Pool

  • Dùng pool để tái sử dụng kết nối:

    • MySQL: mysql2.createPool()

    • MongoDB: Mongoose tự động quản lý pool.

🔸 2. Xử lý kết nối toàn cục (Singleton)

// db.js
const mongoose = require('mongoose');

let conn = null;
async function connectDB() {
  if (conn) return conn;

  conn = await mongoose.connect(process.env.MONGO_URI, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
  });

  return conn;
}

module.exports = connectDB;

🔸 3. Đóng kết nối đúng cách

process.on('SIGINT', async () => {
  await mongoose.disconnect();
  process.exit(0);
});

🔸 4. Xử lý lỗi khi mất kết nối

mongoose.connection.on('error', err => {
  console.error('MongoDB Error:', err);
});

mongoose.connection.on('disconnected', () => {
  console.warn('MongoDB disconnected. Attempting to reconnect...');
});

✅ Tổng kết:

Mục

Nội dung chính

Tương tác DB

Dùng driver (MySQL, MongoDB) hoặc ORM/ODM

Mongoose

ODM giúp define schema, validation, và thao tác Mongo dễ dàng

Quản lý kết nối

Dùng pool, singleton pattern, handle errors và close đúng cách

Tránh rò rỉ bộ nhớ

Không tạo quá nhiều kết nối, đóng kết nối khi không dùng


Last updated