[Node.js] MySQL 연동

Main·2024년 10월 5일
0

MySQL

목록 보기
13/13
post-thumbnail

MySQL 모듈

설치하기

MySQL에 연결하려면 MySQL 모듈을 설치해야 합니다. mysql2 모듈을 설치합니다.

npm install mysql2

주요 메서드와 객체

1 ) createConnection(options)

createConnection 은 MySQL 데이터베이스에 연결하기 위해 단일 연결을 생성합니다. 간단한 데이터베이스 쿼리 작업에 사용됩니다.

  • connection.query(sql, values, callback) : SQL 쿼리를 실행하는 메서드입니다. sql 문자열과 values 배열을 통해 쿼리를 안전하게 수행할 수 있습니다.
  • connection.end() : 연결을 종료합니다. 연결을 종료하지 않으면 리소스가 해제되지 않아 문제가 발생할 수 있습니다.

2 ) createPool(options)

createPool은 데이터베이스 연결 풀을 생성하는 메서드로, 다수의 데이터베이스 연결을 효율적으로 관리할 수 있습니다. 연결 풀을 사용하면 다중 클라이언트 요청을 처리할 때 성능이 향상됩니다.

  • pool.query(sql, values, callback) : 연결 풀 내의 연결을 사용하여 SQL 쿼리를 실행합니다.
  • pool.getConnection(callback) : 풀에서 연결을 직접 가져올 수 있습니다. 이는 특별한 쿼리 작업이 필요한 경우에 유용합니다.
  • pool.end() : 풀을 종료하고 모든 연결을 해제합니다.

💡 연결 풀(Connection Pool) ?

연결 풀(Connection Pool)은 데이터베이스와의 연결을 효율적으로 관리하기 위해 여러 개의 연결을 미리 생성해 두고, 필요할 때마다 이들 연결을 재사용하는 기술입니다. 일반적으로 애플리케이션이 데이터베이스와의 연결을 설정하고 끊는 과정은 상당한 리소스를 소모하기 때문에, 연결 풀을 사용하면 연결의 효율적인 관리와 성능 최적화를 할 수 있습니다.


3 ) createPoolCluster(options)

createPoolCluster 메서드는 여러 데이터베이스 인스턴스를 클러스터로 구성하여 고가용성과 부하 분산을 제공합니다. 주로 main-sub 환경에서 사용됩니다.

  • poolCluster.add(alias, config) : 클러스터에 새로운 연결 풀을 추가합니다. alias는 연결 풀의 식별자입니다.
  • poolCluster.getConnection(pattern, callback) : 특정 패턴(MAIN, SUB)에 맞는 연결을 가져옵니다.

💡 연결 풀 클러스터(Pool Cluster) ?

연결 풀 클러스터(Pool Cluster)는 여러 개의 연결 풀을 그룹화하여 마치 하나의 풀처럼 사용하는 기술입니다. 클러스터를 이용하면 데이터베이스의 고가용성, 부하 분산, 그리고 확장성을 구현할 수 있습니다. 특히 MAIN-SUB 구조로 데이터베이스를 구성했을 때 클러스터 기능을 사용하면 데이터를 읽고 쓰는 작업을 보다 효율적으로 관리할 수 있습니다.


MySQL 사용하기

MySQL 연결하기

MySQL 데이터베이스에 연결할 수 있는 코드를 작성합니다.

const mysql = require('mysql');

// MySQL 연결 설정
const connection = mysql.createConnection({
  host: 'localhost',   // MySQL 서버의 주소
  user: 'root',        // MySQL 사용자명
  password: 'password', // MySQL 비밀번호
  database: 'testdb'    // 사용할 데이터베이스 이름
});

// 연결 시도
connection.connect((err) => {
  if (err) {
    console.error('MySQL 연결 실패:', err.stack);
    return;
  }
  console.log('MySQL에 성공적으로 연결되었습니다.');
});

// 연결 종료
connection.end();

비동기 방식으로 작성하기

mysql2Promise를 지원하므로, 비동기적인 방식으로 코드를 작성할 수 있습니다. async/await를 사용하면 더 깔끔한 코드를 작성할 수 있습니다.

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

let connection;

const connection = async () => {
  try {
    // MySQL 연결 설정 및 비동기 연결 생성
    connection = await mysql.createConnection({
      host: 'localhost',   // MySQL 서버의 주소
      user: 'root',        // MySQL 사용자명
      password: 'password', // MySQL 비밀번호
      database: 'testdb'    // 사용할 데이터베이스 이름
    });

    console.log('MySQL에 성공적으로 연결되었습니다.');
  } catch (err) {
    console.error('MySQL 연결 실패:', err.stack);
  }
};

// 연결 종료 함수
const closeConnection = async () => {
  if (connection) {
    try {
      await connection.end();
      console.log('MySQL 연결이 성공적으로 종료되었습니다.');
    } catch (err) {
      console.error('연결 종료 중 오류가 발생했습니다:', err.stack);
    }
  }
};

(async () => {
	// 연결 시도
  await connectToDatabase();
  // 연결 종료
  await closeConnection();
})();

쿼리 실행하기

MySQL 연결을 통해 데이터를 삽입, 조회, 수정, 삭제할 수 있습니다.

1 ) 데이터 삽입

const user = { name: 'Alice', age: 25 };
const query = 'INSERT INTO users SET ?';

connection.query(query, user, (err, results) => {
  if (err) {
    console.error('데이터 삽입 중 오류 발생:', err);
    return;
  }
  console.log('데이터 삽입 성공:', results.insertId);
});

2 ) 데이터 조회

const selectQuery = 'SELECT * FROM users';

connection.query(selectQuery, (err, results) => {
  if (err) {
    console.error('데이터 조회 중 오류 발생:', err);
    return;
  }
  console.log('조회된 데이터:', results);
});

3 ) 데이터 수정

const updateQuery = 'UPDATE users SET age = ? WHERE name = ?';
const updateData = [30, 'Alice'];

connection.query(updateQuery, updateData, (err, results) => {
  if (err) {
    console.error('데이터 수정 중 오류 발생:', err);
    return;
  }
  console.log('데이터 수정 성공:', results.message);
});

4 ) 데이터 삭제

const deleteQuery = 'DELETE FROM users WHERE name = ?';
const deleteData = ['Alice'];

connection.query(deleteQuery, deleteData, (err, results) => {
  if (err) {
    console.error('데이터 삭제 중 오류 발생:', err);
    return;
  }
  console.log('데이터 삭제 성공:', results.affectedRows);
});

MySQL 예시 코드

nodejs와 MySQL를 연동하여 간단한 CRUD를 구현하는 예시 코드를 살펴보겠습니다.

db 및 table 생성

먼저, testdb와 users 테이블을 생성해줍니다.

아래 쿼리문을 복사하여 database와 table를 생성해주세요.

create database testdb;

use testdb;

CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(100),
  age int
);

MySQL 연결생성

// db/index.js

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

// MySQL에 한 번만 연결 생성
let connection;

const connectToDatabase = async () => {
  if (!connection) {
    try {
      connection = await mysql.createConnection({
        host: 'localhost',
        user: 'root',
        password: 'password',
        database: 'testdb',
      });
      console.log('MySQL에 성공적으로 연결되었습니다.');
    } catch (err) {
      console.error('MySQL 연결 실패:', err.stack);
      throw err;
    }
  }
  return connection;
};

module.exports = connectToDatabase;

userRoutes 생성

// routes/userRoutes.js

const express = require("express");
const router = express.Router();
const connectToDatabase = require("../db");

// 모든 사용자 조회 (GET /users)
router.get("/", async (req, res) => {
  try {
    const connection = await connectToDatabase(); // MySQL 연결 생성
    const [rows] = await connection.query("SELECT * FROM users");
    res.json(rows);
  } catch (err) {
    console.error("데이터 조회 오류:", err);
    res.status(500).json({ error: "데이터 조회 중 오류가 발생했습니다." });
  }
});

// 사용자 수정 (PUT /users/:id)
router.put("/:id", async (req, res) => {
  const { id } = req.params;
  const { name, age } = req.body;

  if (!name || !age) {
    return res.status(400).json({ error: "사용자 이름과 나이를 입력해주세요." });
  }

  try {
    const connection = await connectToDatabase();
    const [result] = await connection.query(
      "UPDATE users SET name = ?, age = ? WHERE id = ?",
      [name, age, id]
    );

    if (result.affectedRows === 0) {
      return res.status(404).json({ error: "해당 사용자를 찾을 수 없습니다." });
    }

    res.json({ message: "사용자 정보가 성공적으로 수정되었습니다." });
  } catch (err) {
    console.error("데이터 수정 오류:", err);
    res.status(500).json({ error: "데이터 수정 중 오류가 발생했습니다." });
  }
});

// 사용자 추가 (POST /users)
router.post("/", async (req, res) => {
  const { name, age } = req.body;

  if (!name || !age) {
    return res.status(400).json({ error: "사용자 이름과 나이를 입력해주세요." });
  }

  try {
    const connection = await connectToDatabase();
    const [result] = await connection.query(
      "INSERT INTO users (name, age) VALUES (?, ?)",
      [name, age]
    );
    res.status(201).json({ message: "사용자가 추가되었습니다.", userId: result.insertId });
  } catch (err) {
    console.error("데이터 삽입 오류:", err);
    res.status(500).json({ error: "데이터 삽입 중 오류가 발생했습니다." });
  }
});

// 사용자 삭제 (DELETE /users/:id)
router.delete("/:id", async (req, res) => {
  const { id } = req.params;

  try {
    const connection = await connectToDatabase();
    const [result] = await connection.query("DELETE FROM users WHERE id = ?", [id]);

    if (result.affectedRows === 0) {
      return res.status(404).json({ error: "해당 사용자를 찾을 수 없습니다." });
    }

    res.json({ message: "사용자가 성공적으로 삭제되었습니다." });
  } catch (err) {
    console.error("데이터 삭제 오류:", err);
    res.status(500).json({ error: "데이터 삭제 중 오류가 발생했습니다." });
  }
});

module.exports = router;

메인 페이지 view 생성(데이터 출력)

// views/index.ejs

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>사용자 목록</title>
</head>
<body>
  <h1>사용자 목록</h1>

  <% if (!data) { %>
    <p>데이터가 존재하지 않습니다.</p>
  <% } else { %>
    <table border="1">
      <thead>
        <tr>
          <th>ID</th>
          <th>이름</th>
          <th>나이</th>
        </tr>
      </thead>
      <tbody>
        <% data.forEach(function(user) { %>
          <tr>
            <td><%= user.id %></td>
            <td><%= user.name %></td>
            <td><%= user.age %></td>
          </tr>
        <% }); %>
      </tbody>
    </table>
  <% } %>
</body>
</html>

app.js 세팅

// app.js

const express = require("express");
const userRoutes = require("./routes/userRoutes");
const connectToDatabase = require("./db"); // DB 연결 모듈 가져오기

const app = express();
const PORT = 8080;

// EJS 템플릿 엔진 설정
app.set("view engine", "ejs");
app.set("views", "./views"); // 템플릿 파일을 views 폴더에서 찾음

// 미들웨어 설정
app.use(express.json()); // JSON 요청 본문 파싱

// 라우터 설정
app.use("/users", userRoutes); // /users 경로로 들어오는 요청을 userRoutes에서 처리

// 기본 루트 경로 - 데이터를 조회하고 EJS로 렌더링
app.get("/", async (req, res) => {
  try {
    const connection = await connectToDatabase(); // MySQL 연결 생성
    const [rows] = await connection.query("SELECT * FROM users"); // MySQL에서 users 테이블 조회

    // 조회한 데이터를 EJS 템플릿으로 렌더링
    if (rows.length === 0) {
      res.render("index", { data: null }); // 데이터가 없을 경우
    } else {
      res.render("index", { data: rows }); // 데이터가 있을 경우
    }
  } catch (err) {
    console.error("데이터 조회 오류:", err);
    res.status(500).send("서버에서 오류가 발생했습니다.");
  }
});

// 서버 시작
app.listen(PORT, () => {
  console.log(`서버가 http://localhost:${PORT} 에서 실행 중입니다.`);
});

Postman를 사용하여 각 메소드별 요청을 보내어 동작을 테스트해보세요.

1 ) 데이터 삽입

2 ) 데이터 조회

3 ) 데이터 수정

4 ) 데이터 삭제

profile
함께 개선하는 프론트엔드 개발자

0개의 댓글