안녕하세요! 오늘은 Spring Framework에서 가장 중요한 기능 중 하나인 @Transactional에 대해 자세히 알아보겠습니다.
@Transactional이란? 🤔
트랜잭션이란 "all or nothing"의 원칙으로 작동하는 작업 단위입니다. 은행 송금을 예로 들면:
- A 계좌에서 돈을 차감하고
- B 계좌에 돈을 추가하는
두 작업이 모두 성공하거나, 모두 실패해야 합니다.
@Transactional 애노테이션은 이러한 트랜잭션 처리를 간단하게 해주는 Spring의 마법 같은 기능입니다!
트랜잭션의 4가지 특성 (ACID) 💫
원자성 (Atomicity)
- 트랜잭션 내 모든 작업은 모두 성공하거나 모두 실패
- 중간 상태는 존재하지 않음
일관성 (Consistency)
- 트랜잭션 전후로 데이터베이스는 일관된 상태를 유지
- 예: 계좌 이체 후 총액은 변하지 않아야 함
격리성 (Isolation)
- 동시에 실행되는 트랜잭션들은 서로 영향을 미치지 않음
- 격리 수준을 통해 제어 가능
지속성 (Durability)
- 성공적으로 완료된 트랜잭션은 영구적으로 반영
- 시스템 장애가 발생해도 데이터는 보존
사용 방법 📝
1. 기본 설정
@Configuration
@EnableTransactionManagement
public class DatabaseConfig {
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
2. 서비스 계층에서 사용
@Service
public class UserService {
@Transactional
public void createUser(User user) {
userRepository.save(user);
emailService.sendWelcomeEmail(user);
// 여기서 예외 발생시 모든 작업이 롤백됨!
}
@Transactional(readOnly = true)
public User getUser(Long id) {
return userRepository.findById(id);
}
}
주요 속성 설명 ⚙️
propagation (전파 옵션)
@Transactional(propagation = Propagation.REQUIRED) // 기본값 @Transactional(propagation = Propagation.REQUIRES_NEW) @Transactional(propagation = Propagation.SUPPORTS)
isolation (격리 수준)
@Transactional(isolation = Isolation.READ_COMMITTED) // 기본값 @Transactional(isolation = Isolation.REPEATABLE_READ) @Transactional(isolation = Isolation.SERIALIZABLE)
timeout (제한 시간)
@Transactional(timeout = 10) // 10초
readOnly (읽기 전용)
@Transactional(readOnly = true) // 읽기 전용 최적화
실제 사용 예시 💡
1. 계좌 이체 서비스
@Service
public class BankService {
@Transactional
public void transfer(String fromAccount, String toAccount, BigDecimal amount) {
Account from = accountRepository.findById(fromAccount);
Account to = accountRepository.findById(toAccount);
from.withdraw(amount);
to.deposit(amount);
accountRepository.save(from);
accountRepository.save(to);
}
}
2. 주문 처리 서비스
@Service
public class OrderService {
@Transactional
public Order createOrder(OrderRequest request) {
// 재고 확인
checkInventory(request);
// 주문 생성
Order order = new Order(request);
orderRepository.save(order);
// 재고 감소
decreaseInventory(request);
// 결제 처리
processPayment(order);
return order;
}
}
주의사항 ⚠️
private 메소드에는 적용되지 않음
- @Transactional은 public 메소드에만 적용
self-invocation 문제
@Service public class UserService { public void method1() { method2(); // @Transactional 적용 안됨! } @Transactional public void method2() { // ... } }
checked exception은 롤백되지 않음
@Transactional(rollbackFor = Exception.class) // 모든 예외에 대해 롤백
성능 최적화 팁 🚀
readOnly = true 활용
- 읽기 전용 작업에는 꼭 설정
- JPA/Hibernate 성능 최적화
적절한 격리 수준 선택
- 기본값인 READ_COMMITTED가 적당
- 필요한 경우에만 높은 격리 수준 사용
트랜잭션 범위 최소화
- 필요한 작업만 트랜잭션 안에 포함
- 긴 트랜잭션은 성능 저하의 원인
참고자료 📚
- Spring 공식 문서: https://docs.spring.io/spring-framework/reference/data-access/transaction.html
- Baeldung @Transactional 가이드: https://www.baeldung.com/transaction-configuration-with-jpa-and-spring
- Spring Blog: https://spring.io/blog/2019/05/16/transaction-management-and-spring
728x90
'300===Dev Framework > Spring' 카테고리의 다른 글
Spring Controller 완벽 가이드 🎯 (3) | 2024.11.14 |
---|---|
Spring Data JDBC: JPA보다 가벼운 ORM의 대안 🚀 (1) | 2024.11.14 |
Spring Properties & Profiles 완벽 가이드 🎯 (0) | 2024.11.14 |
Spring Bean의 생명주기 콜백 메서드 (@PostConstruct & @PreDestroy) 🌱 (2) | 2024.11.14 |
Spring 스케줄링 ⏰ (1) | 2024.11.07 |