본문 바로가기
spring

[Spring] 물리 트랜잭션, 논리 트랜잭션

by goblin- 2024. 11. 28.

물리 트랜잭션과 논리 트랜잭션은 데이터베이스 트랜잭션과 애플리케이션 레이어에서의 트랜잭션 동작을 구분하는 개념으로, 특히 스프링에서의 트랜잭션 관리와 관련하여 자주 언급됩니다.

 

1. 물리 트랜잭션 (Physical Transaction)

 

정의

 

데이터베이스(DB)와 직접적으로 연결된 트랜잭션입니다.

DB 레벨에서 커밋(Commit)과 롤백(Rollback)을 관리합니다.

하나의 Connection을 사용하여 트랜잭션 경계를 설정합니다.

 

특징

 

실제로 DB에서 트랜잭션이 시작되고, 상태가 변경되거나 데이터를 조회합니다.

트랜잭션이 끝날 때 DB에 커밋되거나 롤백됩니다.

 

예시

START TRANSACTION;
-- 데이터 수정
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;

 

2. 논리 트랜잭션 (Logical Transaction)

 

정의

 

애플리케이션 레벨에서의 트랜잭션입니다.

스프링 프레임워크에서는 @Transactional을 통해 논리 트랜잭션을 관리합니다.

여러 논리 트랜잭션이 하나의 물리 트랜잭션에 매핑될 수 있습니다.

 

특징

 

애플리케이션 코드에서 트랜잭션 범위를 설정하고 관리합니다.

논리 트랜잭션은 물리 트랜잭션에 의존하며, 여러 논리 트랜잭션이 같은 물리 트랜잭션 컨텍스트를 공유할 수 있습니다.

트랜잭션 전파(Propagation)에 따라 논리 트랜잭션이 물리 트랜잭션과 독립적으로 실행되거나 하나로 묶일 수 있습니다.

 

3. 물리 트랜잭션과 논리 트랜잭션의 관계

 

관계

 

물리 트랜잭션은 DB와 연결되어 있고, 논리 트랜잭션은 애플리케이션 코드 레벨에서 관리됩니다.

스프링은 물리 트랜잭션을 기반으로 논리 트랜잭션을 관리합니다.

@Transactional로 선언된 메서드가 호출될 때 논리 트랜잭션이 생성됩니다.

 

예시

 

1. 하나의 물리 트랜잭션, 하나의 논리 트랜잭션

 

Repository 구현:

 

OrderRepository

@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
    // JpaRepository를 상속하면 기본적인 CRUD 메서드가 제공됩니다.
}

 

PaymentRepository

@Repository
public interface PaymentRepository extends JpaRepository<Payment, Long> {
    // JpaRepository를 상속하면 기본적인 CRUD 메서드가 제공됩니다.
}

 

ProcessOrder

@Transactional
public void processOrder() {
    orderRepository.save(order);
    paymentRepository.save(payment);
}

하나의 트랜잭션이 시작되고, orderRepositorypaymentRepository의 작업이 같은 물리 트랜잭션 안에서 수행됩니다.

 

2. 하나의 물리 트랜잭션, 여러 논리 트랜잭션

 

OrderService

@Service
public class OrderService {

    @Transactional
    public void saveOrder(Order order) {
        // 주문 저장 관련 비즈니스 로직
        System.out.println("주문 저장 로직 실행");
        orderRepository.save(order);  // 주문 데이터를 데이터베이스에 저장
    }

    @Autowired
    private OrderRepository orderRepository;
}

 

PaymentService

@Service
public class PaymentService {

    @Transactional
    public void processPayment(Payment payment) {
        // 결제 처리 관련 비즈니스 로직
        System.out.println("결제 처리 로직 실행");
        paymentRepository.save(payment);  // 결제 데이터를 데이터베이스에 저장
    }

    @Autowired
    private PaymentRepository paymentRepository;
}

 

processOrder 메서드 (Controller 또는 Main Service)

@Transactional
public void processOrder() {
    orderService.saveOrder();
    paymentService.processPayment();
}

processOrder 메서드에서 @Transactional을 사용하면 하나의 물리 트랜잭션이 생성됩니다.

saveOrderprocessPayment는 같은 물리 트랜잭션을 공유하며 논리적으로 구분됩니다.

 

 

3. 여러 물리 트랜잭션

트랜잭션 전파 속성을 **REQUIRES_NEW**로 설정하면 각 메서드가 독립적인 물리 트랜잭션을 생성합니다.

 

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveOrder() {
    // 독립적인 물리 트랜잭션
    orderRepository.save(order);
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void processPayment() {
    // 독립적인 물리 트랜잭션
    paymentRepository.save(payment);
}

 

4. 물리 트랜잭션과 논리 트랜잭션 요약

 

특징 물리 트랜잭션 논리 트랜잭션
위치 DB 레벨 애플리케이션 레벨
관리 주체 DBMS 스프링 프레임워크
트랜잭션 전파 개념 없음 전파 속성에 따라 논리 트랜잭션 분리 가능
관계 하나의 물리 트랜잭션에 여러 논리 트랜잭션 연결 가능 물리 트랜잭션 없이 독립적으로 존재할 수 없음

 

 

+중요한 추가 포인트

 

트랜잭션 전파(Propagation):

논리 트랜잭션에서 중요한 개념으로, 부모-자식 트랜잭션 간의 관계를 제어합니다.

REQUIRED: 부모 트랜잭션이 있으면 재사용, 없으면 새로 생성.

REQUIRES_NEW: 항상 새로운 물리 트랜잭션 생성.

NESTED: 부모 트랜잭션 내에서 자식 논리 트랜잭션 생성.

트랜잭션 격리 레벨(Isolation Level):

물리 트랜잭션과 밀접한 관련이 있으며, 트랜잭션 간 데이터 읽기/쓰기 간섭을 제어합니다.