JPA 트랜잭션을 제대로 이해하지 않으면 발생하는 장애 사례

Spring Boot에서 @Transactional은 가장 많이 사용하는 기능 중 하나입니다.

 
@Transactional
public void createOrder() {
orderRepository.save(order);
}
 

하지만 트랜잭션을 제대로 이해하지 않고 사용하면 성능 문제, 데이터 오류, Deadlock까지 발생할 수 있습니다.

이번 글에서는 실무에서 자주 발생하는 트랜잭션 문제 7가지를 정리합니다.


1. Self Invocation 문제

Spring 트랜잭션은 AOP Proxy 기반으로 동작합니다.

 
@Service
public class OrderService {

public void create() {
save(); // 트랜잭션 적용 안됨
}

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

이 경우

 
create() → save()
 

내부 호출이기 때문에 Proxy를 거치지 않습니다.

결과

 
@Transactional 적용 안됨
 

해결 방법

서비스를 분리합니다.

 
@Service
public class OrderService {

private final OrderTxService orderTxService;

public void create() {
orderTxService.save();
}
}
 

2. 트랜잭션 안에서 외부 API 호출

이것도 실무에서 많이 발생합니다.

 
@Transactional
public void order() {

paymentApi.call(); // 문제

orderRepository.save(order);
}
 

문제

 
API 호출 동안 DB lock 유지
 

결과

Deadlock
Connection Pool 부족
성능 저하
 

해결 방법

 
외부 API는 트랜잭션 밖에서 실행
 

3. readOnly 옵션 미사용

조회 쿼리에도 트랜잭션을 사용하지만 readOnly 설정을 안 하는 경우가 많습니다.

 

@Transactional
public List<Order> findOrders() {
return orderRepository.findAll();
}
 

이 경우 Hibernate는

 
Dirty Checking
Flush 관리
 

등을 수행합니다.


해결 방법

 
@Transactional(readOnly = true)
 

이렇게 설정하면

Flush 비활성화
성능 개선
 

됩니다.


4. 너무 긴 트랜잭션

 
@Transactional
public void processOrder() {

orderRepository.save(order);

Thread.sleep(3000);

inventoryService.update();
}
 

이 경우

3초 동안 row lock 유지
 

됩니다.

결과

Deadlock
DB lock 증가
 

5. 대량 데이터 처리

 
@Transactional
public void batch() {

List<Order> orders = orderRepository.findAll();

for (Order o : orders) {
o.setStatus("COMPLETE");
}
}
 

문제

Persistence Context 메모리 증가
 

결과

OutOfMemory
성능 저하
 

해결 방법

배치에서는

flush
clear
 

를 사용합니다.


6. 트랜잭션 전파 이해 부족

Spring 트랜잭션에는 여러 propagation 옵션이 있습니다.

 

@Transactional(propagation = Propagation.REQUIRES_NEW)
 

이 옵션은

새 트랜잭션 생성
 

을 의미합니다.

잘못 사용하면

트랜잭션 폭증
성능 문제
 

가 발생할 수 있습니다.


7. Exception 처리 문제

Spring은 기본적으로

RuntimeException
 

만 rollback 합니다.

 
@Transactional
public void order() throws Exception {

orderRepository.save(order);

throw new Exception();
}
 

이 경우

rollback 안됨
 

입니다.


해결 방법

 
@Transactional(rollbackFor = Exception.class)
 

정리

Spring Boot에서 트랜잭션을 사용할 때 반드시 다음을 이해해야 합니다.

AOP Proxy 구조
트랜잭션 범위
Lock 유지 시간
Propagation
Rollback 규칙
 

✔ 핵심 한 줄

@Transactional은 기능이 아니라 동시성 제어 도구다.
LIST

+ Recent posts