스프링 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를 활용한 클라우드 배포 전략을 배워봅시다!
'IT Developer > Spring' 카테고리의 다른 글
Spring 기초 <31. ElasticSearch + Spring Data를 활용한 검색 서비스 구축> (0) | 2025.04.16 |
---|---|
Spring 기초 <30. Spring Cloud Gateway vs API Gateway 차이> (0) | 2025.04.16 |
Spring 기초 <29. Spring Cloud 기반 MSA(Microservices) 아키텍처 설계> (0) | 2025.04.15 |
Spring 기초 <28. Spring Boot와 Kubernetes를 활용한 클라우드 배포 전략> (0) | 2025.04.14 |
Spring 기초 <26. JPA + QueryDSL을 활용한 복잡한 쿼리 최적화> (0) | 2025.04.12 |
Spring 기초 <25. Spring Boot에서 GraphQL API 개발 (Spring GraphQL)> (0) | 2025.04.11 |
Spring 기초 <24. Spring Boot에서 Kafka 이벤트 스트리밍 시스템 구축> (0) | 2025.04.10 |
Spring 기초 <23. Spring Boot에서 Multi-Tenancy 아키텍처 구현> (0) | 2025.04.09 |