You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
AopUtils.isAopProxy() : 선억적 트랜잭션 방식에서 스프링 트랜잭션은 AOP를 기반으로 동작한다. Transactional을 메서드나 클래스에 붙이면 해당 객체는 트랜잭션 AOP 적용의 대상이 되고, 결과적으로 실제 객체 대신에 트랜잭션을 처리해주는 프록시 객체가 스프링 빈에 등록된다.
주입을 받을 때도 실제 객체 대신에 프록시 객체가 주입된다.
클래스 이름을 출력해보면$BasicService$$SpringCGLIB$$0 라고 프록시 클래스의 이름이 출력되는 것을 확인할 수 있다.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
스프링 트랜잭션 이해
1️⃣ 스프링 트랜잭션 소개
✅ 스프링 트랜잭션 추상화
각각의 데이터 접근 기술들은 트랜잭션의 처리하는 방식에 차이가 있음 .
JDBC 트랜잭션 코드 예시)
✅ PlatformTransactionManager 인터페이스
✅ 스프링 트랜잭션 사용 방식
선언적 트랜잭션 관리 vs 프로그래밍 방식 트랜잭션 관리
선언적 트랜잭션 관리(Declarative Transaction Management)
프로그래밍 방식의 트랜잭션 관리(programmatic transaction management)
✅ 선언적 트랜잭션 AOP
2️⃣ 프로젝트 생성
Project : Gradle Project
Language : Java 17
Spring boot version : 3.4.1
Project Metadata
Packaging : Jar
Dependencies
build.gradle
plugins { id 'java' id 'org.springframework.boot' version '3.4.1' id 'io.spring.dependency-management' version '1.1.7' } group = 'hello' version = '0.0.1-SNAPSHOT' java { toolchain { languageVersion = JavaLanguageVersion.of(17) } } configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' //테스트에서 lombok 사용 testCompileOnly 'org.projectlombok:lombok' testAnnotationProcessor 'org.projectlombok:lombok' } tasks.named('test') { useJUnitPlatform() }3️⃣ 트랜잭션 적용 확인
➡️ 스프링 트랜잭션이 적용되는지 확인하는 방법을 알아보자.
proxyCheck() - 실행
$BasicService$$SpringCGLIB$$0라고 프록시 클래스의 이름이 출력되는 것을 확인할 수 있다.proxyCheck() - 실행 결과
@Transcational 은 특정 클래스나 메서드에 하나라도 있으면 트랜잭션 AOP는 프록시를 만들어서 스프링 컨테이너에 등록한다.
실제 basicService 객체 대신에 프록시인
BasicService$$SpringCGLIB$$0를 스프링 빈에 등록한다.프록시는 내부에서 실제 basicService를 참조하게 된다.
핵심은 실제 객체 대신에 프록시가 스프링 컨테이너에 등록되었다는 점
클라이언트인 txBasicTest는 스프링 컨테이너에 @Autowired BasicService basicService로 의존관계 주입을 요청한다. 스프링 컨테이너에는 실제 객체 대신에 프록시가 스프링 빈으로 등록되어 있기 때문 프록시를 주입한다.
프록시는
BasicService를 상속해서 만들어지기 때문에 다형성을 활용할 수 있다. 따라서BasicService대신에 프록시인BasicService$$CGLIB를 주입할 수 있다.basicService$$CGLIB는 트랜잭션을 적용하는 프록시이다.➡️로그 추가
1️⃣ basicService.tx() 호출
basicService.tx() 호출 → 프록시의 tx() 호출 → tx()가 트랜잭션을 사용할 수 있는지 확인
@transactional이 붙어있는 경우 → 트랜잭션 적용 대상
따라서 트랜잭션을 시작한 다음 실제 basicService.tx()를 호출이 끝나서 프록시로 제어가(리턴) 돌아오면 프록시는 트랜잭션 로직을 커밋하거나 롤백해서 트랜잭션을 종료한다.
실행결과
2️⃣ basicService.nonTx() 호출
basicService.nonTx()를 호출하고 종료한다.✅ TransactionSynchronizationManager.isActualTransactionActive()
4️⃣ 트랜잭션 적용 위치
@transactional의 적용 위치에 따른 우선순위를 확인해보자.
스프링에서 우선순위는 항상 더 구체적이고 자세한 것이 높은 우선순위를 가진다.
TxLevelTest
➡️ 우선순위
트랜잭션을 사용할 때는 옵션이 있음 옵션을 주지않으면 어떤 것이 선택되는지 확인해보자.
LevelService의 타입에 @transactional(readOnly = true)
write() : 해당 메서드에 @transactional(readOnly = false)
클래스에 적용하면 메서드는 자동 적용
✅ 인터페이스에 @transactional 적용
🔗 출처
All reactions