MySQL / Node.js + MySQL холбох

Node.js + MySQL холбох

Node.js аппликейшнаас MySQL өгөгдлийн сантай харилцахын тулд mysql2 package ашиглана. Энэ хичээлд connection pool, prepared statement, async/await query бичих аргыг сурна.

mysql2 суулгах

bash
npm install mysql2

mysql2 нь mysql package-ийн сайжруулсан хувилбар бөгөөд Promise дэмжих, prepared statement-ийн найдвартай хэрэгжилттэй.

Энгийн холболт

javascript
const mysql = require("mysql2/promise");

async function main() {
  const connection = await mysql.createConnection({
    host: "localhost",
    user: "root",
    password: "нууц_үг",
    database: "myshop",
  });

  const [rows] = await connection.execute("SELECT * FROM users");
  console.log(rows);

  await connection.end();
}

main();

mysql2/promise импортолж байгаа нь async/await синтакс ашиглах боломж олгоно.

Connection Pool — зөв арга

Аппликейшн дотор query бүрт шинэ холболт нээх, хаах нь удаан бөгөөд нөөц их зарцуулна. Үүний оронд connection pool ашиглана — урьдчилан тогтоосон тооны холболтыг дахин дахин ашиглана.

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

const pool = mysql.createPool({
  host: 'localhost',
  user: 'root',
  password: 'нууц_үг',
  database: 'myshop',
  waitForConnections: true,
  connectionLimit: 10,   -- нэгэн зэрэг хамгийн ихдээ 10 холболт
  queueLimit: 0          -- хүлээлгийн дараалалд хязгааргүй
});

module.exports = pool;

connectionLimit: 10 гэдэг нь нэгэн зэрэг 10 query зэрэг ажиллах боломжтой гэсэн үг.

Pool ашиглан query хийх

javascript
const pool = require('./db');  -- дээрх pool файлаас импортолно

async function getAllUsers() {
  const [rows] = await pool.execute('SELECT * FROM users');
  return rows;
}

async function getUserById(id) {
  const [rows] = await pool.execute(
    'SELECT * FROM users WHERE id = ?',
    [id]
  );
  return rows[0];  -- нэг мөр буцаана
}

async function main() {
  const users = await getAllUsers();
  console.log('Бүх хэрэглэгч:', users);

  const user = await getUserById(1);
  console.log('ID=1 хэрэглэгч:', user);
}

main();

Prepared Statement — SQL Injection-оос хамгаалах

Хэрэглэгчийн оролтыг query-д шууд залгах нь аюултай:

javascript
-- БУРУУ — SQL Injection-д өртөмтгий!
const name = req.body.name;
const query = `SELECT * FROM users WHERE name = '${name}'`;

Хэрэглэгч name' OR '1'='1 оруулбал бүх хэрэглэгчийн мэдээллийг харах боломжтой болно.

Зөв арга — ? placeholder ашиглах:

javascript
-- ЗӨВ — prepared statement
async function findUserByName(name) {
  const [rows] = await pool.execute(
    'SELECT * FROM users WHERE name = ?',
    [name]  -- mysql2 автоматаар аюулгүй болгоно
  );
  return rows;
}

? тэмдэглэгч бүрт утгыг хоёрдугаар аргументийн массиваас дарааллаар нь авна:

javascript
async function createUser(name, email, password) {
  const [result] = await pool.execute(
    'INSERT INTO users (name, email, password) VALUES (?, ?, ?)',
    [name, email, password]
  );
  return result.insertId;  -- шинэ мөрийн ID буцаана
}

CRUD үйлдлүүд

Мэдээлэл нэмэх

javascript
async function createProduct(name, price, stock) {
  const [result] = await pool.execute(
    "INSERT INTO products (name, price, stock) VALUES (?, ?, ?)",
    [name, price, stock],
  );

  console.log("Шинэ бараа ID:", result.insertId);
  console.log("Нэмэгдсэн мөрийн тоо:", result.affectedRows);

  return result.insertId;
}

Мэдээлэл хайх

javascript
async function searchProducts(keyword) {
  const [rows] = await pool.execute(
    "SELECT * FROM products WHERE name LIKE ?",
    [`%${keyword}%`],
  );
  return rows;
}

Мэдээлэл өөрчлөх

javascript
async function updatePrice(productId, newPrice) {
  const [result] = await pool.execute(
    "UPDATE products SET price = ? WHERE id = ?",
    [newPrice, productId],
  );

  if (result.affectedRows === 0) {
    throw new Error("Бараа олдсонгүй");
  }

  return true;
}

Мэдээлэл устгах

javascript
async function deleteUser(userId) {
  const [result] = await pool.execute("DELETE FROM users WHERE id = ?", [
    userId,
  ]);
  return result.affectedRows > 0;
}

Transaction

javascript
async function placeOrder(userId, items) {
  const conn = await pool.getConnection();

  try {
    await conn.beginTransaction();

    -- Захиалга үүсгэх
    const [orderResult] = await conn.execute(
      'INSERT INTO orders (user_id, total) VALUES (?, 0)',
      [userId]
    );
    const orderId = orderResult.insertId;

    let total = 0;

    -- Захиалгын мөрүүд нэмэх
    for (const item of items) {
      await conn.execute(
        'INSERT INTO order_items (order_id, product_id, quantity, price) VALUES (?, ?, ?, ?)',
        [orderId, item.productId, item.quantity, item.price]
      );
      total += item.quantity * item.price;
    }

    -- Нийт дүн шинэчлэх
    await conn.execute(
      'UPDATE orders SET total = ? WHERE id = ?',
      [total, orderId]
    );

    await conn.commit();
    return orderId;

  } catch (err) {
    await conn.rollback();
    throw err;
  } finally {
    conn.release();  -- pool-д буцаана
  }
}

Бүтэн жишээ: Express API

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

const app = express();
app.use(express.json());

const pool = mysql.createPool({
  host: 'localhost',
  user: 'root',
  password: 'нууц_үг',
  database: 'myshop',
  connectionLimit: 10
});

-- Бүх бараа авах
app.get('/products', async (req, res) => {
  try {
    const [rows] = await pool.execute('SELECT * FROM products');
    res.json(rows);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

-- Нэг бараа авах
app.get('/products/:id', async (req, res) => {
  try {
    const [rows] = await pool.execute(
      'SELECT * FROM products WHERE id = ?',
      [req.params.id]
    );
    if (rows.length === 0) {
      return res.status(404).json({ error: 'Бараа олдсонгүй' });
    }
    res.json(rows[0]);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

-- Бараа нэмэх
app.post('/products', async (req, res) => {
  const { name, price, stock } = req.body;
  try {
    const [result] = await pool.execute(
      'INSERT INTO products (name, price, stock) VALUES (?, ?, ?)',
      [name, price, stock]
    );
    res.status(201).json({ id: result.insertId });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

app.listen(3000, () => console.log('Сервер ажиллаж байна: 3000'));

Алдаа зохицуулах

javascript
async function safeQuery(sql, params = []) {
  try {
    const [rows] = await pool.execute(sql, params);
    return { data: rows, error: null };
  } catch (err) {
    console.error("MySQL алдаа:", err.message);
    return { data: null, error: err.message };
  }
}

--Ашиглах;
const { data, error } = await safeQuery("SELECT * FROM users WHERE id = ?", [
  userId,
]);

if (error) {
  console.log("Алдаа гарлаа:", error);
} else {
  console.log("Хэрэглэгч:", data[0]);
}

Дараагийн хичээлд:

Python + MySQL холболт — mysql-connector-python package, cursor, parameterized query ашиглах аргыг үзнэ.