-
[Spring] @Transactional 간략 정리 ( AOP, Proxy, 동작 원리, 특이사항 )IT/JAVA | Spring 2022. 7. 20. 19:38
@Transactional의 동작 원리와 @Transactional을 사용하면서 생기는 이슈들에 대한 간략 정리
1. DB Transaction
- ACID
- 원자성(Atomicity) - 트랜잭션에 속한 각각의 문(데이터를 읽기, 쓰기, 업데이트 또는 삭제하기 위함)을 하나의 단위로 취급합니다. 문 전체를 실행하거나 그 문의 어떤 부분도 실행하지 않거나 둘 중 하나입니다. 이 속성이 있으면 예컨대 스트리밍 데이터 소스가 스트리밍 중에 갑자기 오류를 일으키더라도 데이터 손실과 손상이 방지됩니다.
- 일관성(Consistency) - 트랜잭션이 테이블에 변경 사항을 적용할 때 미리 정의된, 예측할 수 있는 방식만 취합니다. 트랜잭션 일관성이 확보되면 데이터 손상이나 오류 때문에 테이블 무결성에 의도치 않은 결과가 생기지 않습니다.
- 격리(Isolation) - 여러 사용자가 같은 테이블에서 모두 동시에 읽고 쓰기 작업을 할 때, 각각의 트랜잭션을 격리하면 동시 트랜잭션이 서로 방해하거나 영향을 미치지 않습니다. 각각의 요청이 실제로는 모두 동시에 발생하더라도, 마치 하나씩 발생하는 것처럼 발생할 수 있습니다.
- 영속성(Durability) - 트랜잭션 실행으로 인해 데이터에 적용된 변경 사항이 저장되도록 보장합니다. 시스템 오류가 발생해도 마찬가지입니다.
2. @Transactional 동작 원리
- Spring AOP를 이용
- AOP 간단 설명
- Aspect : 반복되어 사용되는 로직
Target : 적용할 로직
Advice : 반복 로직의 구현체
JointPoint, PointCut : Advice의 적용 위치 - 스프링의 어노테이션으로 구현할 수 있다. 또한 AOP는 Bean에만 적용될 수 있다.
- @Before : 어드바이스 타겟 메서드가 호출되기 전에 어드바이스 기능을 수행
@After : 타겟 메서드의 결과에 관계없이(즉 성공, 예외 관계없이) 타겟 메서드가 완료되면 어드바이스 기능을 수행
@AfterReturning(정상적 반환 이후):타겟 메서드가 성공적으로 결괏값을 반환 후에 어드바이스 기능을 수행
@AfterThrowing (예외 발생 이후) : 타겟 메서드가 수행 중 예외를 던지게 되면 어드바이스 기능을 수행
@Around (메소드 실행 전후) : 어드바이스가 타겟 메서드를 감싸서 타겟 메서드 호출 전과 후에 어드바이스 기능을 수행 - 출처: https://engkimbs.tistory.com/746 [새로비]
- Aspect : 반복되어 사용되는 로직
- AOP 간단 설명
- Spring AOP와 Transaction은 Proxy로 동작
- Proxy 패턴
- 대상 객체의 기능을 대신 수행하는 대리 객체를 사용하는 패턴
- 실제 객체가 아닌 임의의 객체를 생성하여 주입
- JDK Proxy와 CGLib Proxy가 있음
- JDK Proxy
- 인터페이스가 없으면 프록시 생성 안됨
- Spring의 AOP default
- CGLib Proxy
- Class의 byte code를 조작하여 프록시 객체를 만듦
- Extends방식으로 프록시 객체를 구현
- JDK 방식보다 성능은 좋으나 여러 문제로 인하여 사용되지 않다가 최근 Spring Boot의 기본 AOP 전략으로 사용 중
- JDK Proxy
- Proxy 패턴
- Call -> AOP Proxy -> Transaction Advisor -> .... -> target Method
- 아래 그림 중 우리가 이해하고 있어야 하는 중요한 요소는 Proxy를 이용하여 Transaction을 동작시킨다는 내용이다.
- 이 Proxy로 인하여 아래에서 다룰 많은 특이사항이 발생한다.
3. @Transactional 적용 특이사항
- Private 접근자는 @Transactional으로 선언할 수 없다.
- Transaction는 Proxy를 이용하고 Proxy를 사용하려면 오버라이딩이 가능해야 한다.
- IDE에서 Private 접근자에 @Transactional을 선언하면 오류 메세지를 띄운다.
- 비 Transaction method에서 Transaction metod를 호출하면 Transaction적용이 안된다.
- 프록시 내부에서 내부를 호출할 때는 Transaction과 같은 부가적인 기능이 적용되지 않는다.
- 호출하려는 target의 Proxy를 통해야 부가기능이 적용된다. ( Ex. 다른 class에 선언되어있는 target method )
public void notTransaction(){ isTransaction(); // Transaction 적용 안된다. } @Transactional public void isTransaction(){ System.out.println("transaction"); throw new RuntimeException(); }
- 같은 Class의 Transaction Method 중복은 의미가 없으며 최초 Transaction을 기준으로 동작한다.
- Transaction option에 따라 설정을 바꿀 수 있으나 기본적인 동작을 의미한다.
- 위에서 설명한 내용과 중복되는 내용이다.
- 프록시는 내부에서 내부를 호출할 때 부가기능이 적용되지 않는다.
- 당연히 같은 Proxy 객체의 서로 다른 Transaction Method를 호출하더라도 최초의 Transaction 외 다른 Transaction은 따로 동작하지 않는다.
@Transactional public void strSave() {...} @Transactional public void intSave() { ... throw new RuntimeException(); } @Transactional public void doubleSave() {...} @Transactional public void save() { strSave(); // intSave()의 transaction에서 Exception이 발생하더라도 save의 모든 method에서 동작이 Rollback된다. // intSave()만 Rollback되길 바랐다면 에상외의 동작에 당황할 수 있다. intSave(); doubleSave(); }
- @Test와 @Transactional이 함께 쓰이는 경우 Rollback이 Default이다.
- Rollback을 원하지 않을 경우 @Rollback(false)로 변경이 가능하다.
- ReadOnly는 동작할 수도 아닐 수도 있다.
- ReadOnly는 읽기 전용이다. JPA의 경우 Transaction 내부 영속성 컨텍스트의 더티 체킹, flush를 발생하지 않는다.
- DB에 따라 DB의 버전에 따라 동작이 달라진다.
- Oracle
- SELECT DML만 지원
- transaction이 시작되기 전 커밋된 데이터에만 접근 가능 ( transaction동안 커밋된 데이터는 반영되지 않음 )
- 일관적인 데이터를 얻도록 보장하기 때문에 성능의 이점 많을 위함은 아니다.
- Mysql
- SELECT DML만 지원
- Oracle과 마찬가지로 스냅샷을 통해 데이터를 조회하기 때문에 데이터 일관성을 보장한다.
- 5.6.5 이상의 버전에서부터 지원한다고 한다.
- Oracle
Checked Exception과 UnChecked Exception의 Transaction Rollback처리는 다음 블로그에서 확인해보자
2022.07.26 - [IT/JAVA | Spring] - [Spring] @Transactional과(와) Checked, Unchecked Exception 간략정리
'IT > JAVA | Spring' 카테고리의 다른 글
[Spring] intellij Spring boot + mybatis + gradle bindingExceptiion (0) 2022.09.09 [Spring] @Transactional과(와) Checked, Unchecked Exception 간략정리 (0) 2022.07.26 [JAVA] interface와 abstract 차이점과 java8의 interface, 다중상속 (0) 2022.07.09 [JAVA] Google Java Style Guide link (0) 2022.07.08 [JAVA] final 키워드 ( variable, method, list, class ) (0) 2022.07.01 - ACID