Spring

[Spring] Spring Boot Transaction 트랜잭션 개념 이해하기

kimslab01 2024. 8. 19. 20:20

 

 

 

 

트랜잭션(Transaction)이란?

 

트랜잭션은 데이터베이스에서 하나의 작업 단위를 말합니다.

이 작업 단위는 여러 개의 작업을 하나의 논리적 작업으로 묶어 처리합니다.

트랜잭션의 중요한 특징은 'ACID'라고 불리는 네 가지 속성을 가지고 있습니다.

 

 

 

1. 원자성(Atomicity)

: 트랜잭션 내의 모든 작업은 전부 성공하거나 전부 실패해야 합니다.

즉, 일부만 성공하고 일부만 실패하는 상황이 발생하면 안됩니다.

이를 위해 트랜잭션 중에 오류가 발생하면 모든 작업을 취소하고, 데이터베이스를 트랜잭션 시작 이전 상태로 되돌립니다.

 

2. 일관성(Consistency)

: 트랜잭션이 완료된 후에도 데이터베이스의 상태는 항상 일관성 있게 유지되어야 합니다.

트랜잭션이 성공적으로 완료되면, 데이터베이스는 정합성을 유지하며 잘못된 데이터 상태가 되지 않도록 합니다.

 

3. 격리성(Isolation)

: 동시에 여러 트랜잭션이 수행되더라도, 각 트랜잭션은 다른 트랜잭션에 영향을 받지 않아야 합니다.

즉, 한 트랜잭션이 완료되기 전까지 다른 트랜잭션이 그 결과를 볼 수 없습니다.

 

4. 지속성(Durability)

: 트랜잭션이 성공적으로 완료되면, 그 결과는 영구적으로 데이터베이스에 반영되어야 합니다.

예를 들어, 시스템이 갑자기 중단되더라도 이미 완료된 트랜잭션의 결과는 데이터베이스에 남아 있어야 합니다.

 

 

 

 

코드를 사용해서 보도록 하겠습니다.

 

 

package com.sparta.memo;

import com.sparta.memo.entity.Memo;
import com.sparta.memo.repository.MemoRepository;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Transactional;

@SpringBootTest
public class TransactionTest {

    @PersistenceContext
    EntityManager em;

    @Autowired
    MemoRepository memoRepository;

    @Test
    @Transactional
    @Rollback(value = false) // 테스트 코드에서 @Transactional 를 사용하면 테스트가 완료된 후 롤백하기 때문에 false 옵션 추가
    @DisplayName("메모 생성 성공")
    void test1() {
        Memo memo = new Memo();
        memo.setUsername("Robbert");
        memo.setContents("@Transactional 테스트 중!");

        em.persist(memo);  // 영속성 컨텍스트에 메모 Entity 객체를 저장합니다.
    }

    @Test
    @Disabled
    @DisplayName("메모 생성 실패")
    void test2() {
        Memo memo = new Memo();
        memo.setUsername("Robbie");
        memo.setContents("@Transactional 테스트 중!");

        em.persist(memo);  // 영속성 컨텍스트에 메모 Entity 객체를 저장합니다.
    }

    @Test
    @Transactional
    @Rollback(value = false)
    @DisplayName("트랜잭션 전파 테스트")
    void test3() {
        memoRepository.createMemo(em);
        System.out.println("테스트 test3 메서드 종료");
    }
}

 

Entity에 해당하는 부분입니다.

 

 

@Transactional
    public Memo createMemo(EntityManager em) {
        Memo memo = em.find(Memo.class, 1);
        memo.setUsername("Robbie");
        memo.setContents("@Transactional 전파 테스트 중!");

        System.out.println("createMemo 메서드 종료");
        return memo;
    }

 

Repository에 해당하는 부분입니다.

 

 

 

 

1. @Transactional 어노테이션

@Test
@Transactional
@Rollback(value = false)
@DisplayName("메모 생성 성공")
void test1() {
    Memo memo = new Memo();
    memo.setUsername("Robbert");
    memo.setContents("@Transactional 테스트 중!");

    em.persist(memo);  // 영속성 컨텍스트에 메모 Entity 객체를 저장합니다.
}

 

@Transactional 어노테이션: 메서드나 클래스에 적용되어 트랜잭션을 관리합니다.

이 어노테이션이 붙어 있는 메서드가 실행될 때, 트랜잭션이 시작됩니다.

 

영속성 컨텍스트(Entity Manager): 이 컨텍스트는 데이터베이스와 상호작용을 관리하는 개체입니다.

em.persist(memo)를 호출하면 새로운 Memo 객체가 데이터베이스에 저장되기 전에 영속성 컨텍스트에 먼저 저장됩니다.

 

Rollback 옵션: 테스트 코드에서 @Transactional을 사용하면, 기본적으로 테스트가 끝난 후 트랜잭션이 자동으로 롤백됩니다.

롤백이란, 트랜잭션 내의 모든 변경 사항을 취소하는 것을 의미합니다.

그러나 여기서는 @Rollback(value = false)로 설정했기 때문에 트랜잭션이 롤백되지 않고 커밋됩니다.

 

 

 

2. 트랜잭션 전파

@Transactional
public Memo createMemo(EntityManager em) {
    Memo memo = em.find(Memo.class, 1);
    memo.setUsername("Robbie");
    memo.setContents("@Transactional 전파 테스트 중!");

    System.out.println("createMemo 메서드 종료");
    return memo;
}

 

이 메서드에서 중요한 부분은 @Transactional입니다.

이 어노테이션은 이 메서드가 호출될 때 트랜잭션을 시작하라는 뜻입니다.

 

트랜잭션 전파(Transaction Propagation): 트랜잭션 전파는 트랜잭션이 어떻게 다른 메서드에 전파되는지 정의합니다.

기본적으로, 이 메서드가 호출될 때, 이미 트랜잭션이 활성화되어 있다면 그 트랜잭션을 그대로 사용하게 됩니다.

그렇지 않다면 새로운 트랜잭션이 시작됩니다.

 

 

 

 

3. 트랜잭션 전파 테스트

@Test
@Transactional
@Rollback(value = false)
@DisplayName("트랜잭션 전파 테스트")
void test3() {
    memoRepository.createMemo(em);
    System.out.println("테스트 test3 메서드 종료");
}

 

여기서 test3 메서드는 createMemo 메서드를 호출합니다.

test3 메서드에도 @Transactional이 붙어 있기 때문에, 이 메서드가 실행될 때 트랜잭션이 시작됩니다.

트랜잭션은 createMemo 메서드에도 전파됩니다.

 

트랜잭션의 흐름: test3 메서드가 실행되면서 트랜잭션이 시작됩니다. 이 트랜잭션은 createMemo 메서드로 전파되어,

createMemo 메서드에서도 동일한 트랜잭션 안에서 작업이 수행됩니다.

만약 createMemo 메서드에서 오류가 발생하면, test3 메서드의 트랜잭션도 전부 롤백됩니다.

 

트랜잭션 전파의 이점: 이렇게 트랜잭션이 전파되면, 여러 메서드에서 수행되는 작업을 하나의 트랜잭션으로 묶어 처리할 수 있습니다.

예를 들어, 여러 메서드에서 DB 업데이트가 일어나더라도, 전체 작업이 성공해야 최종적으로 데이터베이스에 반영되며, 하나라도 실패하면 모든 작업이 취소됩니다.

 

 

 

 

 


 

 

 

 

 

트랜잭션의 개념과 사용 예시를 보며 정리해보았습니다.

질문은 환영입니다!