[Spring Boot] 스프링 트랜잭션과 DB 커넥션의 생명주기

윤하빈·2026년 4월 29일

개발 공부

목록 보기
12/13

1. 스프링의 핵심

스프링과 JPA를 사용할 때 가장 중요한 전제는 DB 커넥션은 한정된 자원이라는 점임.

별도의 설정이 없다면 스프링은 Repository 메서드 단위로 세션을 관리함. 즉, 데이터 조회가 끝나면 즉시 커넥션을 반납하여 다른 요청이 사용할 수 있도록 함.

  • 기본 동작 방식:
  1. findById() 호출 시작 → 세션 오픈(Open) 및 DB 커넥션 점유.
  2. 데이터 조회 완료.
  3. findById() 반환 → 세션 종료(Close) 및 커넥션 반납.

2. 문제 발생: 지연 로딩(Lazy Loading)의 실패

기본 전략대로 세션이 즉시 닫히면, 연관된 데이터를 나중에 가져오려 할 때 문제가 발생함.

void test() {
    Question q = repository.findById(1).get(); // 여기서 세션이 종료됨
    q.getAnswerList().size(); // 세션이 이미 닫혀서 DB 접근 불가
}

3. 해결 방안: @Transactional을 통한 세션 유지

@Transactional 어노테이션은 "이 메서드가 끝날 때까지 세션을 닫지 않는다."는 명령이라고 이해하면 됨.

  • 동작 순서:
    1. 메서드 시작: 트랜잭션이 시작되면서 세션이 열림.
    2. 내부 로직 수행: findById()가 끝나도 트랜잭션 범위 안이라면 세션은 유지됨.
    3. 지연 로딩: 살아있는 세션을 통해 getAnswerList() 등 추가적인 DB 접근이 가능해짐.
    4. 메서드 종료: 트랜잭션이 커밋되거나 롤백되면서 세션이 닫힘.

4. 그렇다면 왜 기본 옵션을 'Lazy'로 설정해 두었나

모든 요청에 대해 세션을 길게 열어두면 편리하겠지만, 치명적인 단점이 있음.

  • 커넥션 고갈: 한 요청이 세션을 오래 붙잡고 있으면, 동시 접속자가 많아질 때 치명적인 문제가 발생함.
  • 서버 부하: 다른 요청들은 커넥션을 얻기 위해 대기해야 하며, 결국 전체 시스템의 응답 속도가 저하됨.

따라서 스프링은 기본은 짧게, 꼭 필요한 곳(로직이 복잡한 곳)에만 @Transactional로 길게 가져가는 효율적인 방식을 가지고 있음.


핵심 요약

  • Repository 메서드 종료 = 세션 종료: DB 커넥션의 효율적인 활용을 위한 스프링의 기본 설계임.
  • @Transactional의 본질: 메서드 실행 전체를 하나의 영속성 세션으로 묶어 지연 로딩을 가능하게 함.
  • 주의 사항: 모든 곳에 남용하기보다, 연관 관계 데이터가 필요한 로직에 전략적으로 사용해야 함.
  • 결국 세션을 언제 열고 닫을지 결정하는 것이 가장 중요하다고 볼 수 있음.

1개의 댓글

comment-user-thumbnail
2026년 4월 29일

베리베리스트로베리 귣잡

답글 달기