Node 강의/주특기 플러스

2-7 DB 연동

kagan-draca 2024. 10. 31. 20:45

DB 컨넥션 Pool을 만들기 위한 사전 작업으로 MySQL을 로컬 환경으로 구성해야 합니다.

 

.env  파일이 현재 아래와 같은데

PORT = 3000

HOST = 127.0.0.1

CLIENT_VERSION = 1.0.0
PORT = 3000

HOST = 127.0.0.1

CLIENT_VERSION = 1.0.0

DB1_NAME = GAME_DB
DB1_USER = 개인의 UserId
DB1_PASSWORD = 개인의 PASSWORD
DB1_HOST = 127.0.0.1
DB1_PORT = 3306

DB2_NAME = USER_DB
DB2_USER = 개인의 UserId
DB2_PASSWORD = 개인의 PASSWORD
DB2_HOST = 127.0.0.1
DB2_PORT = 3306

위와 같이 변경해줍니다.

 

그리고 환경 변수를 새롭게 추가해줬기 때문에 env.js 파일에

import dotenv from 'dotenv';

dotenv.config();

export const PORT = process.env.PORT || 3000;
export const HOST = process.env.HOST || 'localhost';
export const CLIENT_VERSION = process.env.CLIENT_VERSION || '1.0.0';

export const DB1_NAME = process.env.DB1_NAME || 'database1';
export const DB1_USER = process.env.DB1_USER || '개인의 userId';
export const DB1_PASSWORD = process.env.DB1_PASSWORD || '개인의 passward';
export const DB1_HOST = process.env.DB1_HOST || 'localhost';
export const DB1_PORT = process.env.DB1_PORT || 3306;

export const DB2_NAME = process.env.DB2_NAME || 'database2';
export const DB2_USER = process.env.DB2_USER || '개인의 userId';
export const DB2_PASSWORD = process.env.DB2_PASSWORD || '개인의 passward';
export const DB2_HOST = process.env.DB2_HOST || 'localhost';
export const DB2_PORT = process.env.DB2_PORT || 3306;

로 새롭게 DB 정보를 추가해줍니다.

 

그리고 config.js 파일도

export const config = {
  server: {
    port: PORT,
    host: HOST,
  },
  client: {
    version: CLIENT_VERSION,
  },
  packet: {
    totalLength: TOTAL_LENGTH,
    typeLength: PACKET_TYPE_LENGTH,
  },
};

위와 같이 존재하는데 env.js에서 database와 관련된 부분을 추가해줍니다.

 

export const config = {
  server: {
    port: PORT,
    host: HOST,
  },
  client: {
    version: CLIENT_VERSION,
  },
  packet: {
    totalLength: TOTAL_LENGTH,
    typeLength: PACKET_TYPE_LENGTH,
  },
  databases: {
    GAME_DB: {
      name: DB1_NAME,
      user: DB1_USER,
      password: DB1_PASSWORD,
      host: DB1_HOST,
      port: DB1_PORT,
    },
    USER_DB: {
      name: DB2_NAME,
      user: DB2_USER,
      password: DB2_PASSWORD,
      host: DB2_HOST,
      port: DB2_PORT,
    },
    // 필요한 만큼 추가
  },
};

 

src 폴더 아래 db 폴더를 만들어주고 db와 관련된 로직이 작성될 database.js 파일을 만들어줍니다.

import { config } from '../config/config.js';

 

먼저, db 정보를 가지고 있는 config.js 파일의 config를 import 해줍니다.

그리고 우리가 사용할 DB는 MySql이기 때문에 

import mysql from 'mysql2/promise';

을 작성해줍니다.

 

현재 우리는 mysql2 패키지를 프로젝트에 추가하지 않았기 때문에

터미널에서 mysql2를 추가해줍니다.

const { databases } = config;

config에서 databases를 가져오고

 

// 데이터베이스 커넥션 풀 생성 함수
const createPool = (dbConfig) => {
 
};

createPool로 데이터 베이스 커넥션 풀을 생성하고 생성된 풀을 반환해줄 함수를 만들어줍니다.

 

함수 내부에는

  const pool = mysql.createPool({
    host: dbConfig.host,
    port: dbConfig.port,
    user: dbConfig.user,
    password: dbConfig.password,
    database: dbConfig.name,
    waitForConnections: true,
    connectionLimit: 10, // 커넥션 풀에서 최대 연결 수
    queueLimit: 0, // 0일 경우 무제한 대기열
  });

mysql.createPool로 DB Pool을 만들어주겠다고 알리고,

DB 와 관련된 정보와

 

DB Pool에서 connectionLimit로 DB의 요청을 한 번에 최대 10개 까지 처리할 수 있도록 제한해줍니다.

만약 제한된 개수보다 더 많은 요청이 올 경우 waitForConnections로 대기 상태에 걸리게 만들어

앞 선 요청이 모두 완료된 후 처리될 수 있게 해줍니다.

 

queueLimit는 대기 했을 몇개까지 대기 할 수 있는지 지정하는 것으로 0으로 대기열이 무한히 쌓일 수 있게 만들어줍니다.

 

  const originalQuery = pool.query;
 

  pool.query = (sql, params) => {
    const date = new Date();
    // 쿼리 실행시 로그
    console.log(
      `[${formatDate(date)}] Executing query: ${sql} ${
        params ? `, ${JSON.stringify(params)}` : ``
      }`,
    );
    return originalQuery.call(pool, sql, params);
  };

으로 서버가 DB에 요청에 따른 query 내용이 뭔지 볼 수 있게 만들어줍니다.

 

해당 내용에서 fomatDate는

export function formatDate(date) {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');
  const hours = String(date.getHours()).padStart(2, '0');
  const minutes = String(date.getMinutes()).padStart(2, '0');
  const seconds = String(date.getSeconds()).padStart(2, '0');

  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

 으로 utils/dateFormatter.js 파일을 만들어주고 해당 내용을 넣어줬습니다.

 

이렇게 만들어진 DB Pool을 가져다 쓰기 위해서

// 여러 데이터베이스 커넥션 풀 생성
const pools = {
  GAME_DB: createPool(databases.GAME_DB),
  USER_DB: createPool(databases.USER_DB),
};

export default pools;

위와 같이 pools라는 객체를 만들어 GAME_DB에는 database의 GAME_DB로 풀을 만들어 넣어주고,

USER_DB에는 database의 USER_DB로 풀을 만들어 넣어줍니다. 

 

이렇게 만든 DB가 정상 작동하는지 테스트 하기 위해

 

utils/db 폴더를 만들고 testConnection.js 파일을 만들어줍니다.

 

const testDbConnection = async (pool, dbName) => {
  try {
    const [rows] = await pool.query('SELECT 1 + 1 AS solution');
    console.log(`${dbName} 테스트 쿼리 결과:`, rows[0].solution);
  } catch (error) {
    console.error(`${dbName} 테스트 쿼리 실행 중 오류 발생:`, error);
  }
};

위와 같은 함수와 내용을 작성해 1 + 1의 결과를  solution이라는 이름으로 사용할 수 있게 만들어주고, 배열 분해 할당으로 rows 만 가져와 console.log로 rows[0].solution를 출력해줍니다. 1 + 1이 rows의 첫 번째에 들어갈 것이기 때문에 rows[0]을 해준 것이고, AS solution으로 1 + 1을 solution이라 해줬기 때문에 rows[0].solution을 해줍니다. 만약, db query가 정상적으로 안 동작한다면 console.error로 error를 출력해줍니다.

 

const testAllConnections = async (pools) => {
  await testDbConnection(pools.GAME_DB, 'GAME_DB');
  await testDbConnection(pools.USER_DB, 'USER_DB');
};

export { testDbConnection, testAllConnections };

그리고 testDbConnection 함수에 DB 2개인 GAME_DB와 USER_DB를 넣기 위해 위와 같이 함수를 만들어줍니다.

만약, 새로운 DB개 새로 생성된다면 동일한 형식으로 새로 만들어 DB의 정상 작동 유무를 테스트 할 수 있습니다.

 

DB의 동작 테스트는 서버가 처음 시동될 때 확인할 것이기 때문에, 

 

init/index.js의 기존 initServer 함수

const initServer = async () => {
  try {
    await loadGameAssets();
    await loadProtos();
    // 다음 작업
  } catch (e) {
    console.error(e);
    process.exit(1); // 오류 발생 시 프로세스 종료
  }
};

export default initServer;

에서 

const initServer = async () => {
  try {
    await loadGameAssets();
    await loadProtos();
    await testAllConnections(pools);
    // 다음 작업
  } catch (e) {
    console.error(e);
    process.exit(1); // 오류 발생 시 프로세스 종료
  }
};

export default initServer;

으로 수정해줍니다.

 

서버를 동작 시켜 DB 동작 유무를 확인해보면

위와 같이 GAME_DB, USER_DB에서 1 + 1의 결과인 2가 나오는 것을 확인할 수 있습니다.

'Node 강의 > 주특기 플러스' 카테고리의 다른 글

2-9 유저 데이터 저장  (0) 2024.11.01
2-8 DB 마이그레이  (0) 2024.11.01
2-6 세션, 핸들러 추가  (0) 2024.10.31
2-5 패킷 파싱  (0) 2024.10.28
2-4 프로토 파일 로드  (0) 2024.10.22