mariaDB/3. SQL 사용법

mysql. 연결 생성 방식=> createConnection() vs createPool() 차이점

bbomkim 2025. 5. 21. 22:24

 

공통점

항목  createConnection() createPool()
DB 연결 객체 conn conn (getConnection으로 가져옴)
트랜잭션 사용 가능 (beginTransaction, commit, rollback) 가능 (동일하게 사용)
쿼리 실행 conn.query(...) conn.query(...)

둘 다 트랜잭션을 지원하며 쿼리 방식도 동일합니다


차이점

항목  createConnection()  createPool()
연결 개수 1개만 생성 여러 개 (기본은 connectionLimit으로 설정)
재사용성 없음 (직접 관리) 있음 (풀에서 꺼내 쓰고 반환)
병렬 처리 불안정 (모든 요청이 하나의 conn 공유) 안전 (요청마다 독립 conn 제공)
성능 낮음 (연결 매번 생성하거나 공유) 높음 (풀에서 빠르게 할당)
실무 적합성 테스트용 또는 단일 사용자 환경 실무 권장 방식

실제로 많이 쓰는 구조

상황  권장 방식
학습, 테스트, 스크립트 createConnection()
웹 서비스, API 서버 createPool() + getConnection() + release()

한 줄 요약

createConnection()과 createPool()은 둘 다 트랜잭션을 지원하지만,
하나는 연결 하나, 하나는 연결 여러 개 관리한다는 점에서 구조적 차이가 있다.
실무에선 안전성과 확장성 때문에 **풀(pool)**을 반드시 사용한다.

 


실제 예시 코드 (도서구매사이트 : 주문하기 API)

// 주문 하기
async function postOrder(req, res) {
  const { user_id, cart_id_arr, adress, receiver } = req.body;

  // 1. DB 연결 객체 가져오기 (mysql2/promise의 pool에서 connection 하나 가져옴)
  const conn = await pool.getConnection(); 

  let totalPrice = 0;

  try {
    // 2. 트랜잭션 시작 (이 시점부터 수동으로 커밋하기 전까지는 쿼리 결과가 확정되지 않음)
    await conn.beginTransaction();

    // 3. 장바구니(cart) 테이블에서 주문할 도서 목록을 한 번에 조회 (도서 가격 포함)
    const [order_items] = await conn.query(
      `SELECT cart.book_id, cart.count, books.price
       FROM cart
       JOIN books ON cart.book_id = books.id
       WHERE cart.id IN (?)`,
      [cart_id_arr]
    );

    // 4. orders 테이블에 주문 정보 먼저 저장 (총 금액은 아직 0으로 넣어둠)
    const [result_order_insert] = await conn.query(
      `INSERT INTO orders (user_id, adress, receiver, totalPrice)
       VALUES (?, ?, ?, ?)`,
      [user_id, adress, receiver, 0]
    );
    const order_id = result_order_insert.insertId; // 방금 생성된 주문의 고유 ID

    // 5. orderItems 테이블에 주문 상세 정보 저장 + 총 금액 계산
    for (const item of order_items) {
      // 각 주문 항목 저장
      await conn.query(
        `INSERT INTO orderItems (book_id, count, order_id) VALUES (?, ?, ?)`,
        [item.book_id, item.count, order_id]
      );
      // 금액 누적 계산
      totalPrice += item.price * item.count;
    }

    // 6. orders 테이블에 총 금액(totalPrice) 업데이트
    await conn.query(
      `UPDATE orders SET totalPrice = ? WHERE id = ?`,
      [totalPrice, order_id]
    );

    // 7. 주문이 완료되었으므로 장바구니에서 해당 항목들 삭제
    await conn.query(
      `DELETE FROM cart WHERE id IN (?)`,
      [cart_id_arr]
    );

    // 8. 지금까지의 모든 쿼리 실행을 최종적으로 확정(commit)
    await conn.commit();

    // 9. 클라이언트에 성공 응답
    res.status(StatusCodes.OK).end();
  } 
  catch (err) {
    // 10. 중간에 어떤 에러가 발생했다면 지금까지의 모든 작업을 취소 (rollback)
    await conn.rollback();
    console.error("에러 : ", err);
    res.status(StatusCodes.BAD_REQUEST).json({ message: "주문하기 실패" });
  } 
  finally {
    // 11. try든 catch든 상관없이 DB 연결은 반드시 반환해야 다음 요청에서 재사용 가능
    conn.release();
  }
}