728x90
반응형
728x90
스프링 트랜잭션 Spring Transaction
- 스프링 프레임워크에서 데이터베이스의 트랜잭션 관리를 지원하는 핵심 기능
- 스프링은 PlatformTransactionManager 인터페이스를 통해 트랜잭션을 추상화
PlatformTranscationManager
- 스프링 트랜잭션 추상화의 핵심 인터페이스
- 주요 구현체
- DataSourceTransactionManager(JDBC)
- JpaTransactionManager(JPA)
- HibernateTransactionManger(Hibernate)
사용법
- 선언적 트랜잭션 관리
- 스프링은 주로 XML 설정 또는 어노테이션을 통해 트랜잭션을 선언적으로 관리
- @Transactional 어노테이션을 선언하여 사용
- 이름 그대로 해당 로직에 트랜잭션을 적용하겠다고 어딘가에 선언하기만 하면 트랜잭션이 적용되는 방식
- 프로그래밍 방식 트랜잭션 관리
- 프로그래밍적으로 트랜잭션을 제어할 수 있는 API도 제공하며, 필요에 따라 트랜잭션의 시작, 커밋, 롤백 등을 직접 처리할 수 있음
- 직접 트랜잭션에 대한 코드를 작성하여 관리하는 방법
- TransactionTemplate 클래스를 이용한 방법도 가능
선언적 트랜잭션과 AOP
- 선언적 트랜잭션 방식을 사용할 경우 기본적으로 프록시 방식의 AOP가 적용
- 스프링 트랜잭션 관리는 AOP 기반으로 동작
프록시 유형
- JDK 동적 프록시: 인터페이스 기반
- CGLIB 프록시: 클래스 기반, 서브클래싱을 통한 프록시 생성
프록시 도입 전
- 트랜잭션 시작: 비즈니스 로직의 메서드 호출 시 트랜잭션을 직접 시작
- 비즈니스 로직 수행: 트랜잭션 내에서 비즈니스 로직을 수행, 트랜잭션 상태 유지
- 트랜잭션 커밋/롤백: 비즈니스 로직이 성공적이면 커밋, 예외가 발생하면 롤백 -> 직접 커밋과 롤백을 호출
- 트랜잭션 종료: 트랜잭션의 커밋 또는 롤백 후, 트랜잭션 리소스를 정리
프록시 도입 후
- 프록시 생성:
- @Transactional 어노테이션에 따라 트랜잭션 관리 Aspect를 적용하기 위해 프록시를 생성
- 프록시는 실제 비즈니스 로직을 감싸는 역할
- 트랜잭션 처리:
- 비즈니스 로직 메서드가 호출되면 프록시가 트랜잭션을 시작하고 메서드를 호출
- 메서드 실행 전후에 트랜잭션의 커밋 또는 롤백을 처리
- 비즈니스 로직 수행:
- 프록시 내부에서 실제 비즈니스 로직 메서드가 호출
- 메서드는 트랜잭션 관리의 영향을 받으며, 비즈니스 로직은 트랜잭션이 설정된 상태에서 실행
- 트랜잭션 종료:
- 프록시는 비즈니스 로직 메서드의 실행이 완료되면 트랜잭션을 커밋하거나 롤백
- 트랜잭션 관리 로직은 프록시 내부에서 처리되므로 개발자가 직접 트랜잭션을 관리할 필요가 없음
트랜잭션 적용 위치
- 스프링에서의 우선순위는 항상 더 구체적이고 자세한 것이 높은 우선순위를 가짐
- 메서드와 클래스에 어노테이션을 붙일 수 있다면 구체적인 메서드가 우선으로 적용
트랜잭션 AOP 주의 사항
- @Transactional은 스프링 트랜잭션 AOP가 적용
- 트랜잭션 AOP 방식은 기본적으로 프록시를 사용
- 트랜잭션이 적용되기 위해선 무조건 프록시를 통해 호출이 되어야 함
1. 객체 내부에서 메서드 호출이 일어나는 경우
- @Transcational이 붙어 있지 않은 external() 메서드 호출
- 트랜잭션이 적용되지 않기 때문에 프록시를 통해서 호출되는 것이 아니라 실제 객체 인스턴스를 호출
- 호출된 메서드 내에서 같은 객체 내부 메서드인 internal() 메서드를 호출(internal() 메서드는 @Transactional)
- @Transactional로 트랜잭션이 적용되기 위해서는 프록시를 통해 메서드가 호출되어야 하지만 internal()은 현재 접근 중인 객체의 내부 메서드이므로 this.internal()을 통해 메서드가 직접 호출됨
- 프록시를 통해 호출되지 않았으므로 @Transactional 어노테이션이 붙어있지만 트랜잭션이 적용되지 않음
해결방안
- 기본 this 포인터를 통해 호출되지 않게 해당 메서드를 별도의 클래스로 분리하여 사용
- 자기 자신을 객체로 가지는 self 참조를 통해 메서드를 호출
2. 초기화 시점 사용
- @PostConstruct를 통한 초기화 시점에서 @Transactional을 사용할 경우 적용되지 않음
- 초기화 코드가 먼저 호출되고 그다음 트랜잭션 AOP가 적용
해결방안
- ApplicationReadyEvent 사용
- ApplicationReadyEvent는 트랜잭션 AOP를 포함한 스프링이 컨테이너가 완전히 생성되고 난 다음에 이벤트가 붙은 메서드를 호출하여 트랜잭션 적용가능
@Transactional 옵션
- rollbackFor: 특정 예외가 발생할 때 트랜잭션을 롤백하도록 지정
- noRollbackFor: 특정 예외가 발생해도 트랜잭션을 롤백하지 않도록 지정
- isolation: 트랜잭션의 격리 수준
- DEFAULT: 데이터베이스의 기본 격리 수준을 사용
- READ_UNCOMMITTED: 가장 낮은 격리 수준으로, 커밋되지 않은 데이터도 읽을 수 있음
- READ_COMMITTED: 커밋된 데이터만 읽을 수 있음
- REPEATABLE_READ: 트랜잭션이 시작된 이후에는 읽은 데이터가 일관되게 유지
- SERIALIZABLE: 가장 높은 격리 수준
- timeout: 트랜잭션 타임아웃 설정
- readOnly: 트랜잭션이 읽기 전용인지 지정(Default = false)
- propagation: 트랜잭션의 전파 행동을 정의
테스트 주의 사항
- @Transactional을 테스트 메서드에 사용할 경우 테스트 완료 후 자동 롤백
- 실제 커밋 동작 테스트 시 @Commit 어노테이션 사용 필요
스프링 DB 2편 - 데이터 접근 활용 기술 강의 | 김영한 - 인프런 (inflearn.com) 강의 내용 참고
728x90
'백엔드 > Spring' 카테고리의 다른 글
| [Spring] 변경 감지 & 병합 (0) | 2024.09.06 |
|---|---|
| [Spring] 스프링 트랜잭션 전파 Propagation (0) | 2024.09.05 |
| [Spring] MyBatis (1) | 2024.09.01 |
| [Spring] JDBC Template (3) | 2024.08.31 |
| [Spring] 예외 처리 (1) | 2024.08.30 |