IT Developer/Spring

Spring 기초 <27. Spring Boot에서 트랜잭션 관리 최적화 (@Transactional, REQUIRES_NEW)>

TEMA_ 2025. 4. 13. 13:40
반응형

스프링 Spring

27. Spring Boot에서 트랜잭션 관리 최적화 (@Transactional, REQUIRES_NEW)

 

안녕하세요! 태마입니다.

Spring 기초 강좌입니다.

 

강좌의 경우 

1. 주제 간단 정리

2. 상세 주제 정리

으로 이루어져 있습니다.

 

스프링 Spring

포스팅 시작하겠습니다 :)

 


 

1. 주제 간단 정리

 

1. 트랜잭션(Transaction)이란?

트랜잭션은 데이터베이스의 연산(INSERT, UPDATE, DELETE 등)을 하나의 단위로 묶어 실행하는 개념
모든 연산이 성공해야 트랜잭션이 커밋(Commit)되며, 하나라도 실패하면 롤백(Rollback)됨

📌 트랜잭션의 ACID 원칙

원칙설명
Atomicity (원자성) 트랜잭션 내 모든 작업이 완료되거나 모두 롤백됨
Consistency (일관성) 데이터베이스의 상태가 항상 유효하도록 유지됨
Isolation (고립성) 트랜잭션이 서로 간섭하지 않고 독립적으로 실행됨
Durability (지속성) 트랜잭션이 완료되면 결과가 영구적으로 저장됨

📌 트랜잭션을 활용하면 "데이터 정합성을 보장하며, 장애 발생 시 롤백 가능"


2. Spring Boot에서 트랜잭션 관리 방법

Spring Boot에서는 @Transactional을 활용하여 트랜잭션을 쉽게 관리 가능

📌 Spring의 트랜잭션 관리 방식

방식설명
프로그래밍 방식 EntityManager를 직접 사용하여 트랜잭션을 관리
선언적 방식 (@Transactional) Spring AOP를 활용하여 트랜잭션을 자동으로 적용

📌 Spring에서는 선언적 트랜잭션 (@Transactional)이 일반적으로 사용됨


✅ 여기까지 트랜잭션의 개념과 Spring Boot에서의 기본적인 트랜잭션 관리 방식을 배웠습니다!
👉 "그렇다면, Spring Boot에서 트랜잭션을 어떻게 최적화할까?"
✅ 2부에서 Spring Boot에서 @Transactional과 Propagation.REQUIRES_NEW를 활용한 트랜잭션 최적화 방법을 배워봅시다!

 

반응형

 


 

2. 상세 주제 정리

 

1. @Transactional 기본 사용법

Spring에서 @Transactional을 사용하면 해당 메서드 실행 시 자동으로 트랜잭션이 시작되고, 예외 발생 시 롤백됨

📌 기본적인 @Transactional 적용 (UserService.java)

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Transactional
    public void createUser(String name, String email) {
        User user = new User(name, email);
        userRepository.save(user);
    }
}

@Transactional을 적용하면 해당 메서드 실행 시 트랜잭션이 시작됨
예외 발생 시 자동으로 롤백됨

📌 Spring Boot에서는 "트랜잭션을 자동으로 관리할 수 있어 코드가 간결해짐"


2. @Transactional(propagation = Propagation.REQUIRES_NEW) 활용

기본적으로 @Transactional은 부모 트랜잭션을 따르지만, Propagation.REQUIRES_NEW를 사용하면 새로운 트랜잭션을 생성함

📌 REQUIRES_NEW를 활용한 트랜잭션 관리 (UserService.java)

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {

    private final UserRepository userRepository;
    private final AuditService auditService;

    public UserService(UserRepository userRepository, AuditService auditService) {
        this.userRepository = userRepository;
        this.auditService = auditService;
    }

    @Transactional
    public void createUser(String name, String email) {
        User user = new User(name, email);
        userRepository.save(user);

        auditService.logUserCreation(user); // 별도의 트랜잭션으로 실행
    }
}

📌 Audit 로그 저장을 별도의 트랜잭션으로 실행 (AuditService.java)

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class AuditService {

    private final AuditRepository auditRepository;

    public AuditService(AuditRepository auditRepository) {
        this.auditRepository = auditRepository;
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void logUserCreation(User user) {
        AuditLog log = new AuditLog("User Created: " + user.getName());
        auditRepository.save(log);
    }
}

Propagation.REQUIRES_NEW를 사용하면 기존 트랜잭션과 독립적으로 실행됨
즉, createUser()에서 오류가 발생해도 logUserCreation()은 정상적으로 커밋됨

📌 REQUIRES_NEW를 활용하면 "서로 다른 트랜잭션을 분리하여 안정적인 데이터 저장 가능"


3. @Transactional을 활용한 트랜잭션 롤백 전략

Spring에서는 특정 예외 발생 시 트랜잭션을 롤백할 수 있도록 설정 가능

📌 예외 발생 시 트랜잭션 롤백 설정 (UserService.java)

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Transactional(rollbackFor = Exception.class)
    public void createUser(String name, String email) throws Exception {
        User user = new User(name, email);
        userRepository.save(user);

        if (email.contains("error")) {
            throw new Exception("Invalid email format!");
        }
    }
}

rollbackFor = Exception.class를 설정하면 Exception이 발생할 경우 롤백됨

📌 트랜잭션 롤백을 활용하면 "데이터 정합성을 유지하며, 비정상적인 데이터 저장을 방지 가능"


4. @Transactional(readOnly = true)를 활용한 성능 최적화

읽기 전용 쿼리에서는 @Transactional(readOnly = true)를 적용하여 성능을 최적화 가능

📌 읽기 전용 트랜잭션 설정 (UserService.java)

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;

@Service
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Transactional(readOnly = true)
    public List<User> getUsers() {
        return userRepository.findAll();
    }
}

readOnly = true를 설정하면 변경 감지를 하지 않아 성능 최적화 가능

📌 읽기 전용 트랜잭션을 활용하면 "불필요한 데이터 변경 감지를 줄여 성능을 최적화 가능"


✅ 여기까지 Spring Boot에서 트랜잭션 관리 최적화 방법을 배웠습니다!
👉 "그렇다면, Spring Boot와 Kubernetes를 활용한 클라우드 배포 전략은 어떻게 할까?"
✅ 다음 회차에서 Spring Boot와 Kubernetes를 활용한 클라우드 배포 전략을 배워봅시다!

 

반응형