트랜잭션(Transaction)이란 무엇이고, ACID 특성에 대해 설명해주세요.

김상욱·2024년 12월 14일

트랜잭션(Transaction)이란 무엇이고, ACID 특성에 대해 설명해주세요.

트랜잭션(Transaction)?

트랜잭션은 데이터베이스에서 논리적인 작업의 단위를 의미. 주로 하나의 작업을 처리하기 위해 여러 개의 작업(쿼리)이 실행될 수 있는데, 이 모든 작업을 하나의 단위로 묶어서 처리하는 것을 트랜잭션이라고 함.

트랜잭션은 데이터베이스의 상태를 한 상태에서 다른 상태로 변화 시키는 작업을 의미하며, 모든 작업이 성공적으로 완료되거나, 문제가 발생하면 모두 취소(롤백, rollback)되어야 한다.

Commit : 트랜잭션 내의 모든 작업이 성공적으로 완료되면 데이터베이스에 영구적으로 반영
Rollback : 트랜잭션 내의 일부 작업이 실패하면 모든 작업을 취소하고 데이터베이스를 이전 상태로 복구

트랜잭션은 데이터 무결성과 일관성을 보장하기 위해 매우 중요하다.

ACID?

트랜잭션이 데이터베이스의 무결성과 일관성을 유지하기 위해 따라야할 4가지 주요 특성

Atomicity(원자성) : 트랜잭션의 모든 작업이 모두 성공하거나, 모두 실패해야 함을 보장. 부분적으로 실행된 상태는 존재하지 않음.

Consistency(일관성) : 트랜잭션이 실행되기 전과 후에 데이터베이스는 항상 일관된 상태를 유지해야 함. 트랜잭션은 데이터 무결성 제약 조건을 항상 만족해야 함.

Isolation(격리성) : 하나의 트랜잭션이 실행 중일 때, 다른 트랜잭션이 해당 작업에 영향을 주지 않도록 해야 함. 여러 트랜잭션이 동시에 실행될 때도 각 트랜잭션이 독립적으로 실행된 것과 동일한 결과를 보장.

Durability(지속성) : 트랜잭션이 성공적으로 커밋되면, 해당 변경 내용은 영구적으로 반영되어야 함. 시스템 장애가 발생하더라도 데이터는 손실되지 않도록 보장


신입 및 취준생 Java, Spring 백엔드 개발자의 입장에서 트랜잭션(Transaction)과 ACID 특성을 이해하고 활용하기 위해 실습할 수 있는 몇 가지 방법과 아이디어를 정리해 드릴게요.


1. 간단한 데이터베이스 트랜잭션 실습

목표: 기본적인 트랜잭션 처리와 롤백/커밋의 동작 이해하기
내용: JDBC를 활용해 직접 트랜잭션 처리 코드 작성

실습 단계:

  1. 사전 준비:

    • H2 Database (간단하고 경량 DB로 로컬 실습에 적합)
    • Java JDBC 연결 설정
  2. 예제: 은행 계좌 이체 시뮬레이션:

    • 두 개의 테이블 준비:
      CREATE TABLE Account (
          id INT PRIMARY KEY,
          name VARCHAR(50),
          balance INT
      );
      INSERT INTO Account VALUES (1, 'Alice', 1000);
      INSERT INTO Account VALUES (2, 'Bob', 1000);
    • JDBC를 사용해 다음 작업 수행:
      • Alice 계좌에서 200원 출금
      • Bob 계좌에 200원 입금
      • 트랜잭션 중간에 예외를 발생시켜 롤백 테스트
  3. JDBC 코드 예시:

    Connection conn = null;
    try {
        conn = DriverManager.getConnection(DB_URL, USER, PASSWORD);
        conn.setAutoCommit(false); // 트랜잭션 시작
    
        // Alice 계좌에서 출금
        PreparedStatement pstmt1 = conn.prepareStatement("UPDATE Account SET balance = balance - 200 WHERE id = 1");
        pstmt1.executeUpdate();
    
        // Bob 계좌에 입금
        PreparedStatement pstmt2 = conn.prepareStatement("UPDATE Account SET balance = balance + 200 WHERE id = 2");
        pstmt2.executeUpdate();
    
        conn.commit(); // 성공 시 커밋
    } catch (Exception e) {
        if (conn != null) conn.rollback(); // 실패 시 롤백
        e.printStackTrace();
    } finally {
        if (conn != null) conn.close();
    }

2. Spring Framework에서 @Transactional 실습

목표: Spring의 트랜잭션 관리와 @Transactional의 동작 이해

실습 단계:

  1. 프로젝트 세팅:

    • Spring Boot 프로젝트 생성 (JPA와 H2 Database 의존성 추가)
  2. 데이터베이스 설정:

    • 간단한 Account 엔터티 생성:

      @Entity
      public class Account {
          @Id
          @GeneratedValue(strategy = GenerationType.IDENTITY)
          private Long id;
          private String name;
          private int balance;
      }
    • 데이터 초기화:

      INSERT INTO Account (name, balance) VALUES ('Alice', 1000), ('Bob', 1000);
  3. 서비스 레이어 트랜잭션 처리:

    • @Transactional을 활용해 이체 기능 구현:

      @Service
      public class AccountService {
          @Autowired
          private AccountRepository accountRepository;
      
          @Transactional
          public void transferMoney(Long fromId, Long toId, int amount) {
              Account fromAccount = accountRepository.findById(fromId).orElseThrow();
              Account toAccount = accountRepository.findById(toId).orElseThrow();
      
              fromAccount.setBalance(fromAccount.getBalance() - amount);
              toAccount.setBalance(toAccount.getBalance() + amount);
      
              accountRepository.save(fromAccount);
              accountRepository.save(toAccount);
      
              // 예외 강제로 발생 (롤백 테스트용)
              if (toAccount.getBalance() > 1500) {
                  throw new RuntimeException("Balance too high!");
              }
          }
      }
  4. 테스트:

    • 정상 동작 시 데이터가 커밋되고, 예외 발생 시 롤백되는지 확인.

3. ACID 특성 확인하기

Atomicity (원자성) 확인:

  • @Transactional로 묶은 작업에 일부 실패를 강제로 발생시켜 롤백되는지 확인.

Consistency (일관성) 확인:

  • 트랜잭션 전후 데이터 상태를 비교하여 무결성 제약 조건(예: balance >= 0)이 유지되는지 확인.

Isolation (격리성) 확인:

  • 트랜잭션 격리 수준 설정 실습:
    spring:
      datasource:
        url: jdbc:h2:mem:testdb
        username: sa
        password:
      jpa:
        properties:
          hibernate.connection.isolation: 2 # READ_COMMITTED
  • 동시에 여러 트랜잭션을 실행하여 READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE의 차이를 관찰.

Durability (지속성) 확인:

  • 트랜잭션 성공 후 데이터가 영구 저장되는지 확인.

4. 추가적으로 실습할 만한 내용

  • Spring AOP와 트랜잭션 관리:

    • @Transactional 내부 동작 원리 확인.
    • AOP를 사용해 트랜잭션 시작 및 종료 로직을 직접 구현해 보기.
  • 동시성 이슈 및 격리 수준 실습:

    • 동일한 데이터를 여러 스레드에서 업데이트할 때 발생하는 문제 확인.
    • 이를 해결하기 위한 격리 수준 설정 실험.
  • 실제 프로젝트에 응용:

    • 간단한 쇼핑몰이나 게시판 서비스에서 트랜잭션을 적용하여 주문 처리나 게시글 작성 시 데이터 일관성을 보장.

5. GitHub에 실습 코드 업로드

  • 실습 결과를 정리하고 GitHub에 올려 포트폴리오로 활용하세요.
  • 각 실습 주제에 대한 설명과 테스트 결과를 README에 추가하면 가독성이 높아집니다.

이러한 실습은 트랜잭션의 개념뿐 아니라, Spring Boot의 동작 방식과 데이터베이스 관리 능력을 키우는 데 효과적입니다. 필요한 부분에 대해 추가로 설명이 필요하면 말씀해주세요! 😊

0개의 댓글