- 시작하게 된 계기 및 다짐 😮
이번 코드스테이츠의 백엔드 엔지니어링 개발자 부트캠프
에 참여하게 되면서 현직개발자 분들의 빠른 성장을 위한 조언 중 자신만의 블로그를 이용하여 배운 것 들을 정리하는게 많은 도움이 된다 하여 시작하게 되었다.
- 학습 목표 😮
목표 | 결과 |
---|---|
트랜잭션(Transaction)이 무엇인지 이해 | O |
Spring에서 지원하는 트랜잭션 방식을 이해 | O |
트랜잭션이 적용되지 않은 애플리케이션에서 어떤 문제점이 발생할 수 있는지 이해 | O |
- 정리 😮
1. 트랜잭션(Transaction)이란?
2. ACID 원칙
1. 원자성(Atomicity)
3. 커밋(Commit) 과 롤백(Rollback)
커밋
롤백
4. Commit 호출과정
TransactionImpl
★ 트랜잭션 제어를 위한 트랜잭션 드라이버 구현체 획득
JdbcResourceLocalTransactionCoordinatorImpl > TransactionDriverControlImpl
★ JDBC Connection 액세스 방법을 제공하는 객체 획득
AbstractLogicalConnectionImplementor
JdbcConnection
1). commit = prepareCommand("COMMIT", commit);
2). commit.executeUpdate(null);
Command
1). commitIfNonTransactional();
2). session.rollback();
3). boolean autoCommit = session.getAutoCommit();
4). session.commit(true);
SessionLocal 클래스
1). transaction.commit();
Extra. JDBC,JPA 이란
0. @애너테이션
1. Spring Boot에서의 트랜잭션 설정
애너테이션 방식의 트랜잭션
1).클래스 레벨에 적용
2). 메서드 레벨에 적용
클래스 레벨에 @Transactional을 추가한것에 추가적으로 메서드에 @Transactional(readOnly =true) 를 추가
하면 읽기 전용 트랜잭션이 적용된다.
이 경우, commit을 해도 영속성 컨텍스트가 flush 되지 않고 변경 감지를 위한 snapshot 생성도 따로 하지않음( 1차 캐시에는 저장되어, 같은 조회시 이를 사용, SELECT문만 사용가능)
일부 메서드에 @Transactional이 되어있지 않으면, 클래스 레벨 @Transactional적용
2. 여러 작업이 하나의 트랜잭션으로 묶이는 경우
트랜잭션 전파(Transcation Propagation)
트랜잭션의 경계에서 진행 중인 트랜잭션이 존재할 때 또는 존재하지 않을때 어떻게 동작할 것인지 결정
1). Propagation.REQUIRED
- (Default값)으로, 진행 중인 트랜잭션이 없을시 새로시작하고, 있으면 해당 트랜잭션에 참여
2). Propagation.REQUIRES_NEW
- 무조건 새로 트랜잭션을 시작하고, 기존의 트랜잭션은 새로 시작된 트랜잭션이 종료시까지 중지
3). Propagation.MANDATORY
- 진행중인 트랜잭션이 없으면 새로 싲가하지만, 있다면 예외를 발생
4). Propagation.NOT_SUPPORTED
- 트랜잭션을 필요로 하지 않음, 진행 중인 트랜잭션이 있으면 메서드 종료까지 트랜잭션이 중지
5). Propagation.NEVER
- 트랜잭션이 필요하지 않음, 진행 중인 트랜잭션이 있을시 예외 발생
트랜잭션 격리 레벨(Isolation Level)
1). Isolation.DEFAULT
2). Isolation.READ_UNCOMMITTED
3). Isolation.READ_COMMITTED
4). Isolation.REPEATABLE_READ
5). Isolation.SERIALIZABLE
3. AOP 방식의 트랜잭션 적용
[예제 Code]
@Configuration
public class TxConfig {
private final TransactionManager transactionManager;
// (2)
public TxConfig(TransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
@Bean
public TransactionInterceptor txAdvice() {
NameMatchTransactionAttributeSource txAttributeSource =
new NameMatchTransactionAttributeSource();
// (3)
RuleBasedTransactionAttribute txAttribute =
new RuleBasedTransactionAttribute();
txAttribute.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// (4)
RuleBasedTransactionAttribute txFindAttribute =
new RuleBasedTransactionAttribute();
txFindAttribute.setPropagationBehavior(
TransactionDefinition.PROPAGATION_REQUIRED);
txFindAttribute.setReadOnly(true);
// (5)
Map<String, TransactionAttribute> txMethods = new HashMap<>();
txMethods.put("find*", txFindAttribute);
txMethods.put("*", txAttribute);
// (6)
txAttributeSource.setNameMap(txMethods);
// (7)
return new TransactionInterceptor(transactionManager, txAttributeSource);
}
@Bean
public Advisor txAdvisor() {
// (8)
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* com.codestates.coffee.service." +
"CoffeeService.*(..))");
return new DefaultPointcutAdvisor(pointcut, txAdvice()); // (9)
}
}
(1) AOP방식으로 트랜적션 적용을 위해 @Configuration 애너테이션을 추가하며 Configuration 클래스를 정의
(2) 애플리케이션에 트랜잭선 적용을 위해 TransactionManager 객체를 받음(DI)
(3) 트랜잭션 어드바이스용 TransactionInterceptor 빈을 등록하고 이를 이용해 트랜잭션 경계를 설정 및 트랜잭션 적용
- (3)을 이용하여 조회 메서드를 제외한 공통 트랜잭션 애트리뷰트적용
- (4)을 이용하여 조회 메서드에 적용하기 위한 트랜잭션 적용
(5) 트랜잭션을 적용할 메서드에 트랜잭션 애트리뷰트 매핑하는 과정으로, 각
- Key : 메서드 이름, value : 적용할 애트리뷰트 를 추가해준다.
(6) map객체를 트랜잭션 애트리뷰트 Source에 넣음
txAttributeSource.setNameMap(txMethods) 해당 어드바이스용 TransactionInterceptor 생성자 파라미터로 객체 생성 및 리턴
(8) 포인트 컷 지정하는 과정으로, 위에서 만든 TransactionInterceptor 객체를 타켓 클래스에 적용하기 위한 포인트 컷을 지정
(9) 마지막으로 (9)와 같이 DefaultPointcutAdvisor의 생성자 파라미터로 포인트컷과 어드바이스를 전달
Extra. 이벤트 발생(EventListner)
@애너테이션
1). @EnableAsync
2). @Async
3). @EventLinster
4). @TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
트랜잭션이 성공적으로 commit이 되기 전/후/마무리 되었을 때를 기준으로 실행
ApplicationEventPublisher 클래스
MemberRegistrationApplicationEvent 클래스
MemberRegistrationEventListener 클래스
- 피드백 😮
트랜잭션을 이용하여 하나의 작업이 전부 성공or실패에 따라 전체를 성공시킬지 취소시킬지 결정하는 방식을 학습하였다.
이는, 데이터의 일관성을 위해 사용한다.
특정 상황이 발생하였을 때 동작시키는 EventListener를 이용하여 어떤 상황이 발생하였을때 동작하는 방식을 학습하였다.
- 앞으로 해야 될 것 😮