-
Spring Transactional 뜯어보기스터디 2024. 5. 15. 19:16
Transaction 이란 ?
- 데이터베이스의 상태를 변화시키기 위해 수행하는 작업의 단위
- 데이터베이스의 상태를 변경시킨다는 말 은 SELECT, UPDATE, INSERT, DELETE 와 같은 행동을 뜻한다.
Transaction의 특징
- 원자성(Atomicity)
- 원자성은 트랜잭션이 DB에 모두 반영되거나, 전혀 반영되지 않거나를 뜻한다.
- 일관성(Consistency)
- 일관성은 트랜잭션 작업 처리의 결과가 항상 일관되어야 한다를 뜻한다.
- 데이터 타입이 변경 전후가 같아야 한다
- 독립성(Isolation)
- 어떤 하나의 트랙잭션의 다른 트랙젹션의 연산에 끼어들 수 없다
- 지속성
- 트랙잭션이 완료된 후에, 결과가 데이터베이스에 영구적으로 반영되어야 한다
Commit과 Rollback
- Commit이란 하나의 트랜잭션이 성공적으로 끝났고, 데이터베이스가 일관성있는 상태에 있을 때, 하나의 트랜잭션이 끝났다라는 것을 뜻한다
- Rollback이란 하나의 트랜잭션 처리가 비정상적으로 종료되어 트랜잭션의 원자성이 깨진경우, 트랜잭션을 처음부터 다시 시작하거나, 트랜잭션의 부분적으로만 연산된 결과를 다시 취소시킨다
Spring에서 Transaction을 사용하는 법
우리가 알다시피 이런식으로 annotation을 달아주면 transaction이 적용이 된다
그렇다면 내부적으로는 어떻게 동작하는 걸까?
@Service public class TestService { @Transactional public void test() { } public void test2() { } }
Transactional 파훼하기
이렇게 한다면
- Spring Configuration에 @EnableTransactionManagement을 붙인다(Spring에서 자동적으로해줌)
- Spring Configuration에서 자동적으로 Transaction Manager를 지정해준다
이런식으로 업데이트가 된다
데이터베이스 마다 TransactionManager가 다른데, Spring에서 자동적으로 처리해준다.
그러면 나
Transaction 파훼하기 2탄
근데 사실 Transactional Annotation의 비밀은 따로 있다
바로 Proxy객체를 생성한다는 것이다
Proxy객체를 생성후에, 우리가 Annotation으로 등록했던 실제 service를 호출하는 방식으로 사용이 된다.
그렇다면
Spring IOC Container가 proxy 만드는것은 인정할게, 그럼 transaction의 open, close, commit 등과 같은 과정들은 누가 할건데 ?
그걸 바로 ‘transactionManager’ 가 합니다.
그래서 실제는 아래와 같은 그림으로 작동을 합니다.
선언적 트랙젹션의 문제점
@Service public class MemberService { private final MemberRepository memberRepository; public MemberService(MemberRepository memberRepository) { this.memberRepository = memberRepository; } @Transactional public void memberInserts(List<Member> members) { members.forEach(this::memberInsert); } public void memberInsert(Member member) { memberRepository.save(member); } }
이런식으로 작성이 되면, Transactional이 적용되지 않는다
같은 클래스 내에서 메소드를 호출할 때 AOP가 적용되지 않는 이유는 프록시 객체를 통하지 않고 원본 객체의 메소드를 직접 호출하기 때문입니다.
따라서 이런식으로 클래스를 분리해줘야 한다
@Service public class MemberService { private final MemberRepository memberRepository; private final MemberInsertService memberInsertService; public MemberService(MemberRepository memberRepository, MemberInsertService memberInsertService) { this.memberRepository = memberRepository; this.memberInsertService = memberInsertService; } public void memberInserts(List<Member> members) { members.forEach(memberInsertService::memberInsert); } } @Service public class MemberInsertService { private final MemberRepository memberRepository; public MemberInsertService(MemberRepository memberRepository) { this.memberRepository = memberRepository; } @Transactional public void memberInsert(Member member) { memberRepository.save(member); } }
프로그래밍 적 트랜잭션 구현
privat final PlatformTransactionManager transactionManager; public void pointPlus() { DefaultTransactionDefinition def = new DefaultTransactionDefinition(); def.setName("pointTransaction"); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); TransactionStatus status = transactionManager.getTransaction(def); try { pointDao.plusPoint(); } catch (MyException ex) { transactionManager.rollback(status); throw ex; } txManager.commit(status); }
JDBC에서 또한 위와 같은 식으로 트랙젹션을 실행한다
https://blogshine.tistory.com/291
자세한 내용은 위에 링크 보기
알게된 점
- Transactional Annotation은 결국 transactionManager을 사용하여 Transaction을 처리한다
- Transactional Annotation이 메소드에 적용된 경우, 같은 클래스에서 메소드를 호출할 경우에는 프록시객체가 아닌 원본객체를 호출하게 되기에 Transactional이 적용되지 않는다
궁금한점
- 분산 트랙잭션은 어떻게 처리되는가 ?
- Transactional Annotation의 인자들을 어떻게 적절히 활용하여 성능적으로 최대한 끌어올릴 수 있을까?
'스터디' 카테고리의 다른 글
Spring Annotation 의 내부구조 동작원리 (0) 2024.06.09 JAVA 병렬 프로그래밍 (0) 2024.06.09 Spring Tomcat 분석 (0) 2024.05.01 SQL Query 최적화 (Spring JPA, Go gorm) (1) 2024.03.15 Spring JPA (0) 2024.01.24