Spring FrameWork에서의 트랜잭션 처리

한주영·2023년 5월 8일
0

코드스테이츠 학습

목록 보기
20/24

선언형 방식의 트랜잭션 적용

1.스프링 로직(비즈니스 로직)에 애너테이션 추가

2.AOP를 이용해서 비즈니스로직에서 트랜잭션 적용코드를 감추는 방식

@Configuration
@EnableTransactionManagement
public class JpaConfig{

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(){
        final LocalContainerEntityManagerFactoryBean em = 
				new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        ...
        ...

        return em;
    }

		// (1)
    @Bean
    public DataSource dataSource() {
        final DriverManagerDataSource dataSource = new DriverManagerDataSource();
				
				...
				...

        return dataSource;
    }

    @Bean
    public PlatformTransactionManager transactionManager(){
        JpaTransactionManager transactionManager
                = new JpaTransactionManager();    // (2)
        transactionManager.setEntityManagerFactory(
                entityManagerFactoryBean().getObject() );
        return transactionManager;
    }
}

데이터베이스 커넥션 정보를 담는Datasource가 필요함

Spring에서 트랜잭션은 기본적으로 PlatformTransactionManager에 의해 관리,
해당 인터페이스를 구현해서 데이터 액세스 기술에 맞게 유연하게 트랜잭션을 적용 할수 있도록 추상화 되어있음

애너테이션 방식의 트랜잭션 적용

@Transactional 애너테이션을 트랜잭션이 필요한 영역에 추가해 주면 된다.

MemberService클래스에 트랜잭션을 적용한 코드 일부


import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional   // (1)
public class MemberService {
    private final MemberRepository memberRepository;

    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    public Member createMember(Member member) {
        verifyExistsEmail(member.getEmail());

        return memberRepository.save(member);
    }

}

rollback 동작 유무 확인

예외 발생시 rollback이 잘 되는지 확인 하고 싶을땐
강제로 예외가 발생하도록 수정을 하면된다

public Member createMember(Member member) {
        verifyExistsEmail(member.getEmail());
        Member resultMember = memberRepository.save(member);

		//강제로 예외가 발생하도록 처리한 부분 		
        if (true) {   
            throw new RuntimeException("Rollback test");
        }
        return resultMember;
    }

클래스 레벨과 메서드 레벨의 적용순서

@Transactional 애너테이션을 추가할때 트랜잭션 적용

클래스 레벨에만 @Transactional이 적용된 경우
->클래스 레벨의 @Transactional 애너테이션이 메서드에 일괄적용

클래스 레벨과 메서드 레벨이 함께 적용된 경우
->메서드 레벨의 @Transactional이 적용된다.

AOP를 이용한 트랜잭션 처리

import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.interceptor.*;
import java.util.HashMap;
import java.util.Map;

// (1)
@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.@Configuration애너테이션 추가, 클래스정의
2.TransactionManager 객체가 필요 -> 해당객체를 DI받는다
3.트랜잭션 어드바이스용 TransactionInterceptor빈 등록
-트랜잭션 애트리뷰트 지정
-트랜잭션 적용할 메서드에 애트리뷰트 매핑
-TransactionInterceptor 객체 생성
4.Advisor객체 생성

profile
백엔드개발자가 되고싶은 코린이:)

0개의 댓글