카카오 부트캠프/내용 정리

node.js express에서 MySQL 트랜잭션 적용

BCSJH 2024. 11. 21. 22:26

트랜잭션(Transaction)이란?

트랜잭션은 데이터베이스의 일관성과 무결성을 유지하기 위해 여러 SQL 작업을 하나의 단위로 묶어 처리하는 기능입니다.
트랜잭션은 아래 4가지 특징을 보장하며 데이터의 신뢰성을 높입니다.

특징설명
원자성트랜잭션 내의 모든 작업이 완전히 수행되거나 전혀 수행되지 않음
일관성트랜잭션 완료 후 데이터베이스가 항상 일관된 상태를 유지
격리성동시에 실행되는 트랜잭션이 서로 영향을 미치지 않음
지속성트랜잭션이 완료되면 변경 사항이 영구적으로 저장

트랜잭션 명령어

트랜잭션은 START TRANSACTION, COMMIT, ROLLBACK 명령어로 제어합니다.

명령어설명
START TRANSACTION트랜잭션 시작
COMMIT모든 작업을 영구적으로 저장
ROLLBACK작업 취소 및 이전 상태로 되돌림

MySQL은 기본적으로 자동 커밋 모드가 활성화되어 있습니다. 트랜잭션으로 작업을 묶으려면 명시적으로 **START TRANSACTION**을 사용해야 합니다.

MySQL에서 트랜잭션 사용하기

아래는 MySQL 콘솔에서 트랜잭션을 사용하는 예시입니다.

트랜잭션 실행 예시

  1. 트랜잭션 시작
    START TRANSACTION;
  2. 데이터 수정
    UPDATE accounts SET balance = balance - 100 WHERE id = 1;
    UPDATE accounts SET balance = balance + 100 WHERE id = 2;
  3. 변경 사항 저장 (COMMIT)
  4. 변경 취소 (ROLLBACK)

트랜잭션 사용 전후 결과

  • 트랜잭션 사용 전: 명령 하나가 실패해도 다른 작업은 반영됨.
  • 트랜잭션 사용 후: 모든 작업이 성공하거나 실패 시 모두 취소됨.

Express.js에서 트랜잭션 적용하기

Express.js에서 MySQL과 트랜잭션을 활용하려면 mysql2 라이브러리를 사용합니다. 아래는 사용자 탈퇴 시 트랜잭션을 적용하는 예제입니다.

1. 기존 코드 (트랜잭션 미적용)

exports.deleteUser = async (user_id) => {
  try {
    await pool.promise().query(`DELETE FROM innodb.users WHERE user_id = ?`, [user_id]);
    await pool.promise().query(`DELETE FROM innodb.boards WHERE user_id = ?`, [user_id]);
    await pool.promise().query(`DELETE FROM innodb.comments WHERE user_id = ?`, [user_id]);
  } catch (error) {
    console.error('Error deleting user:', error);
    return false;
  }
};

2. 개선된 코드 (트랜잭션 적용)

exports.deleteUser = async (user_id) => {
  const connection = await pool.promise().getConnection();
  try {
    // NOTE : 트랜잭션 시작
    await connection.beginTransaction();

    // NOTE : 사용자 삭제
    await connection.query(`DELETE FROM innodb.users WHERE user_id = ?`, [user_id]);

    // NOTE : 게시글 삭제
    await connection.query(`DELETE FROM innodb.boards WHERE user_id = ?`, [user_id]);

    // NOTE : 댓글 삭제 (의도적 에러 발생)
    throw new Error('Intentional error for rollback test');

    // NOTE : 트랜잭션 커밋
    await connection.commit();
    return true;
  } catch (error) {
    // NOTE : 롤백
    await connection.rollback();
    console.error('Transaction rolled back due to error:', error);
    return false;
  } finally {
    // NOTE : 연결 반환
    connection.release();
  }
};

주요 변경점

  1. 트랜잭션 시작 및 종료:
    • beginTransaction(): 트랜잭션 시작.
    • commit(): 모든 작업 성공 시 저장.
    • rollback(): 에러 발생 시 모든 작업 취소.
  2. 에러 핸들링:
    • try...catch를 사용해 오류를 탐지하고 적절히 처리.
    • 에러 발생 시 rollback() 호출.
  3. 연결 반환:
    • finally 블록에서 connection.release()로 연결을 반환해 리소스 누수 방지.

테스트

  • 성공 케이스:
    • user_id에 해당하는 데이터가 모두 정상 삭제되고 커밋됩니다.
  • 실패 케이스:
    • 의도적으로 에러를 발생시켜 롤백이 제대로 작동하는지 확인합니다.

트랜잭션을 사용하면 데이터베이스의 무결성과 안정성을 유지할 수 있습니다. 여러 테이블에서 데이터를 삭제하거나 수정하는 작업에서 트랜잭션을 사용하면 유용할 것 같습니다. 실무에서는 정말 수많은 테이블이 존재해서 트랜잭션을 사용하는 경우가 많습니다. 문제 없이 데이터 처리가 가능하면 좋겠지만, 에러는 언제 어디서 발생할지 모르기 때문에 트랜잭션에 대해서 잘 알아두면 좋습니다. 😉