백엔드 개발자에게는 DB는 중요한 리소스이기 때문에 DB공부도 필수이다!
여기에 @Transactional 이라는 개념이 무엇일까 알아보자
여러작업들을 하나로 묶은 단위입니다. 한 덩어리의 작업들은 모두 실행되거나, 실행되지 않는다. (all-or-nothing)
은행에서 내 계좌에서 돈을 빼고 누군가에게 이체를 했는데 그때 에러가 생겨서 내계좌에서만 돈이빠져나가고 상대방은 이체를 못받은 경우는 없을것이다.
돈이 빠져나가고 이체되는과정은 하나의 Trasaction으로 묶여서 모두 성공하거나 실패하게 만든다
즉, 문 전체를 실행하거나 그 문의 어떤 부분도 실행하지 않거나 둘 중 하나입니다. 이 속성이 있으면 예컨대 스트리밍 데이터 소스가 스트리밍 중에 갑자기 오류를 일으키더라도 데이터 손실과 손상이 방지한다.
모든 DB 테이블의 자료들은 항상 정해진 규칙에 맞춰서 자료가 저장되어있어야하고 트랜잭션이 종료된 시점(Commit)에 Consistency가 맞춰져 있어야한다.
트랜잭션의 까다로운 특징 중 하나
성능과 tradeoff 관계가 있다.
DB를 가장 고립성이 높으면 성능은 떨어지고 DB가 고립성이 낮은상태는 성능이 높을 수 있다.
Isolation Level을 잘 조절해서 로직을 짜야한다.
지속성은 커밋이 되는 시점에서 커밋된 이력은 무조건 남아있어도록 보장을한다.
시스템 오류가 발생하여도 변경사항을 저장한다.
Spring이 어떤 전략을 가지고 Transaction을 제공하고 편의성을 제공하고있는지 알아볼 예정이다
@Transactional 애노테이션을 메소드나 클래스에 추가를 한다면 TransactionInterceptor에서 invoke 메소드의 매개변수인 MethodInvocation값에 들어가게된다. 그래서 이 메소드 즉 invocation된 메소드를 통해서 targetClass의 정보도 가져오게 된다.
MethodInvocation
A method invocation is a joinpoint and can be intercepted by a method interceptor.
즉, MethodInvocation은 조인포인트이다.
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
@Override
@Nullable
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
@Override
public Object getTarget() {
return invocation.getThis();
}
@Override
public Object[] getArguments() {
return invocation.getArguments();
}
});
}
여기 invokeWithinTransaction을 타고 들어간다면 오류가 생길때 rollback처리를 해주는 기능이라던가 commit을 해주는 기능들이 구현이 되어있다!
그렇기 때문에 @Transactional 애노테이션을 사용했을때 AOP 트랜잭션의 기능들을 손쉽게 쓸수있음을 알 수 있었다.