1.

프로그래밍 방식 트랜잭션 정리

프로그래밍 방식 트랜잭션 관리는 다음과 같은 경우에 유리합니다.

  • 세밀한 제어가 필요한 경우:
  • 복잡한 비즈니스 로직이나 특정 조건에 따라 트랜잭션의 경계를 유연하게 제어해야 할 때.
  • 예외 처리 로직 구현:
  • 일부 로직만 롤백하거나, 특정 예외 발생 시 다른 보상 로직을 추가로 구현할 때 유용합니다.

 

@Transactional 어노테이션은 여러 속성을 지원합니

  • propagation: 트랜잭션 전파 규칙을 설정합니다. (예: REQUIRED, REQUIRES_NEW 등)
  • isolation: 트랜잭션 격리 수준을 설정합니다.
  • readOnly: 읽기 전용 트랜잭션으로 최적화할 수 있습니다.
  • rollbackFor: 롤백 대상으로 처리할 예외를 지정할 수 있습니다.

 

2. 동시성 문제 개념 및 사례 분석

 

이번 학습에서는 동시성 문제의 개념과 필요성을 이해하며, 데이터 정합성이 깨질 수 있는 다양한 상황과 실무에서 발생할 수 있는 문제를 다룹니다. 이를 위해 주문 처리나 재고 관리 시스템과 같은 사례를 통해 동시성 문제가 실제로 어떤 영향을 미치는지 살펴보고, Dirty Read, Non-Repeatable Read, Phantom Read, Lost Update와 같은 대표적인 동시성 문제의 동작 원리와 발생 조건을 학습합니다.

트랜잭션 격리 수준은 데이터 정합성시스템 성능 사이의 트레이드오프(Trade-off) 관계에 있습니다.

  • 대부분의 애플리케이션: Read Committed 수준으로 충분합니다. 데이터 부정합 문제의 가장 큰 원인인 Dirty Read를 막아주면서 좋은 성능을 보장합니다.
  • 데이터의 일관성이 중요한 경우: 하나의 트랜잭션 내에서 조회한 값이 변하지 않아야 한다면 Repeatable Read를 고려할 수 있습니다.
  • 극도의 정합성이 요구되는 경우: 동시성 저하를 감수하고서라도 데이터 불일치가 절대로 발생해서는 안 되는 시스템이라면 Serializable을 사용해야 합니다.

MySQL 격리 수준 변경

MySQL에서 트랜잭션 격리 수준을 설정하여 트랜잭션 간의 동작 방식을 제어할 수 있습니다. 격리 수준은 데이터베이스 전체(Global) 또는 특정 세션(Session)에 대해 설정 가능합니다.

 

 Dirty Read

READ UNCOMMITTED

격리 수준에서 발생하는 심각한 데이터 부정합 문제입니다. 이 문제를 해결하기 위해서는 최소

READ COMMITTED

이상의 격리 수준을 사용해야 합니다

 

 

이번 학습에서는 트랜잭션 격리 수준의 개념과 종류를 이해하고, 이를 활용해 동시성 문제를 해결하는 방법을 배웁니다. 먼저 트랜잭션의 ACID 원칙을 복습하며, 격리 수준이 데이터 정합성과 시스템 성능에 미치는 영향을 살펴봅니다.

Read Uncommitted,Read Committed,Repeatable Read,Serializable

등 네 가지 격리 수준의 특징과 동작 방식을 학습하며, 각각이 Dirty Read, Non-Repeatable Read, Phantom Read와 같은 동시성 문제에 어떤 영향을 미치는지 분석합니다. 이를 바탕으로 적절한 격리 수준을 설정해 동시성 문제를 해결하는 방법을 익히고, MySQL 실습을 통해 각 격리 수준에서 발생하는 문제를 재현하고 해결 과정을 경험함으로써 데이터 정합성을 유지하는 실질적인 기술을 습득합니다.

 

 

4. DB 락 메커니즘 이해와 실습

이번 학습에서는 데이터베이스 락의 개념과 이를 활용해 데이터 충돌을 방지하는 방법을 배웁니다. 비관적 락(Pessimistic Lock)은 데이터를 선점해 충돌을 방지하는 방식이며, 낙관적 락(Optimistic Lock)은 충돌이 발생했을 때 버전 검사를 통해 문제를 해결합니다. 두 방식의 차이와 활용 사례를 살펴보고, Shared Lock과 Exclusive Lock, 테이블 레벨 락과 행(Row) 레벨 락의 특징을 통해 락의 다양한 종류를 이해합니다. 또한, 비관적 락을 활용한 재고 관리와 낙관적 락을 이용한 데이터 충돌 방지 실습을 통해 락을 효과적으로 적용하는 방법을 익힙니다.

 

. 비관적 잠금(Pessimistic Locking)

  • 데이터를 업데이트하기 전에 해당 행을 잠금(Lock) 처리하여 다른 트랜잭션이 접근하지 못하도록 합니다.

비관적 락은 여러 사용자가 동시에 동일한 데이터를 수정하려고 시도할 때 데이터 정합성을 유지하는 데 적합합니다.

 

. 낙관적 잠금(Optimistic Locking)

  • 데이터에 version 필드를 추가하고, 업데이트 시 조건으로 사용합니다.
  • 트랜잭션이 변경한 데이터가 다른 트랜잭션에 의해 변경되었는지 확인하고, 충돌 시 롤백 처리합니다.

데이터를 읽을 때는 락을 사용하지 않으며, 데이터를 수정할 때 버전 번호를 통해 충돌 여부를 판단합니다.

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Lock;

import jakarta.persistence.LockModeType;

public interface ProductRepository extends JpaRepository<Product, Long> {

  @Lock(LockModeType.PESSIMISTIC_WRITE)
  @Query("SELECT p FROM Product p WHERE p.id = :id")
  Optional<Product> findByIdForUpdate(@Param("id") Long id);

  @Lock(LockModeType.PESSIMISTIC_WRITE)
  Optional<Product> findFirstByName(String name);    
}

 

LIST

+ Recent posts