트랜잭션과 스프링에서의 트랜잭션

dropKick·2023년 4월 23일
0

스터디

목록 보기
5/20

목표

  • 트랜잭션에 정의에 대해서 이해한다.
  • 자바에서 트랜잭션의 구현을 이해한다.
  • 스프링 프레임워크에서 트랜잭션을 처리하는 방법과 그 사례를 알아본다.

트랜잭션

  • 일상생활에서 Transaction은 상품, 서비스, 자산 등을 교환하기 위한 구매자와 판매자간 계약 또는 커뮤니케이션을 의미함
  • 이를 컴퓨터과학에서는 쪼갤 수 없는 일련의 과정으로 이어지는 업무처리의 단위로써 사용
  • 예) 전자상거래 사이트에서 고객이 구매하는 경우
    • 제품의 선택, 결제 정보 입력, 결제 확인, 최종 결제 처리의 과정 중 일어나는 일련의 프로세스들(주문 정보 동기화, 결제 정보 유효성 검증, 신용카드 유효성 검증, 최종 결제)은 한꺼번에 실행되어 저장(Commit) 되어야 하고, 하나의 단계라도 실패할 시 전체 트랜잭션이 동일한 상태로 복귀(Rollback) 되어야 함

데이터베이스 트랜잭션

  • 데이터의 무결성을 위해 트랜잭션은 대부분 데이터베이스와 연결되어 있음
  • 트랜잭션의 시작과 끝은 언제나 모두 동일해야 함
  • 이를 위해 여러 DBMS들은 트랜잭션을 유지하기 위한 방법을 사용하고 있음

트랜잭션의 특징

트랜잭션은 데이터의 무결성이 지켜지기 위한 작업을 위해 특징을 가지고 있음

  1. 원자성(Atomicity)
    트랜잭션 연산은 데이터베이스에 모두 반영되든지 아니면 전혀 반영되지 않아야 함
    트랜잭션 내의 모든 명령은 반드시 완벽히 수행되어야 하며, 어느 하나라도 오류가 발생하면 트랜잭션 전부가 취소되어야 함
  2. 일관성(Consistency)
    트랜잭션이 실행을 성공적으로 완료시 언제나 일관성 있는 데이터베이스 상태로 변환됨
    시스템이 가지고 있는 고정 요소는 트랜잭션 수행 전과 트랜잭션 수행 완료 후의 상태가 같아야 함
  3. 격리성(Isolation)
    둘 이상의 트랜잭션이 동시에 병행 실행되는 경우, 어느 하나의 트랜잭션 실행 중 다른 트랜잭션의 연산이 끼어들 수 없음. 수행 중인 트랜잭션은 완료될 때까지 다른 트랜잭션에서 수행 결과를 참조할 수 없음
  4. 영구성(Durability)
    성공적으로 완료된 트랜잭션의 결과는 시스템이 고장나더라도 영구적으로 반영되어야 함

트랜잭션의 수행

  • 트랜잭션은 4가지 특징을 이용하여 All or Nothing의 연산을 수행
  • All or Nothing을 구현하기 위한 연산으로 CommitRollBack이 존재
Commit

  • 모든 작업들을 정상적으로 처리하겠다고 확정하는 명령어로 처리 과정을 데이터베이스에 영구적으로 저장
  • 커밋 수행 시 하나의 트랜잭션 과정이 종료되고 이전 데이터가 완전히 업데이트 됨
Rollback

  • 작업 중 문제 발생으로 인해 트랜잭션의 처리 과정에서 발생한 변경 사항 취소하는 명령어로 트랜잭션의 일부가 정상적으로 처리돼도 트랜잭션이 행한 모든 연산이 취소 됨
  • 원자성 구현
    • 트랜잭션 시작되기 이전의 상태로 Rollback
      • 마지막 커밋을 완료한 시점의 커밋 명령까지만 정상 처리된 상태로 유지하고 커밋된 데이터까지만 복구
    • 트랜잭션의 재시작 또는 폐기
      • 마지막 커밋 명령 이후 수행한 모든 DML 작업들을 취소시켜 이전 상태로 원상 복귀

스프링에서 트랜잭션의 처리

  • 스프링 프레임워크는 Spring Data JPA의 @Transactional 어노테이션을 이용하여 트랜잭션 처리를 지원

@Transactional

@Transactional의 특징

  • 클래스, 메소드에 @Transactional 어노테이션을 사용가능, 이를 통해 선언전 트랜잭션이 적용
  • 선언전 트랜잭션은 Spring AOP를 통해 프록시 구현체를 생성하여 해당 작업을 수행할 클래스, 메소드를 감싸 전후로 CommitRollback을 지원
    • 프록시 패턴만이 가능한 장점으로, 우리는 커밋, 롤백 기능을 직접적으로 호출하지 않고 해당 기능을 가진 상위 프록시 객체에게 맡겨 처리할 수 있음

@Transactional의 실제 동작


1. 실행할 로직에 대한 호출이 들어오면 Spring AOP Proxy가 이를 가로챔(Intercept)
2. Spring AOP Proxy 객체는 Transaction Advisor를 호출
3. Transaction Advisor는 Commit 또는 Rollback 등의 트랜잭션 처리를 수행
4. 트랜잭션 처리 외에 다른 부가 기능을 처리하기 위해 Custom Advisor를 호출하고 수행
5. Advisor에서 부가 기능 처리를 마치면 원래 호출했던 로직을 수행
6. Interceptor chain을 따라 caller에게 결과를 다시 전달

트랜잭션의 처리

Spring Data JPA @Transcational을 이용한 경우

import org.springframework.transaction.annotation.Transactional;

@RequiredArgsConstructor
@Transactional(readOnly = true)
@Service
public class UserService implements UserDetailsService {
    private final UserRepository userRepository;

    public void addUsers(List<User> userList) {
        for (User user : userList) {
            if (isEmailNotDuplicated(user.getEmail())) {
                userRepository.save(user);
            }
        }
    }
    
    // 메소드
        @Transactional
    public void update(Long id, String password, Address address, String name) {
        User user = userRepository.findById(id).orElse(null);

        // 더티 체킹 (상태 변경 검사)
        assert user != null;
        user.updateUser(password, name, address);
    }
}

JPA(Java Persistant API) 구현체를 이용한 경우

import javax.persistence.*;

public class JpaMain {

    public static void main(String[] args) {

        // 엔티티 매니저 팩토리 생성
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabook");
        EntityManager em = emf.createEntityManager(); // 엔티티 매니저 생성

        EntityTransaction tx = em.getTransaction(); // 트랜잭션 기능 획득

        try {
            tx.begin(); // 트랜잭션 시작
            logic(em);  // 비즈니스 로직
            tx.commit(); // 트랜잭션 커밋
        } catch (Exception e) {
            e.printStackTrace();
            tx.rollback(); //트랜잭션 롤백
        } finally {
            em.close(); //엔티티 매니저 종료
        }

        emf.close(); //엔티티 매니저 팩토리 종료
    }

    public static void logic(EntityManager em) {

        String id = "id1";
        Member member = new Member();
        member.setId(id);
        member.setUsername("류원혁");
        member.setAge(2);

        // 등록
        em.persist(member);

        // 수정
        member.setAge(28);

        //삭제
        em.remove(member);
        
    }
}

번외, Spring에서 Transaction을 다양한 구현체로 사용 가능한 이유

  • Spring은 트랜잭션 기술의 공통점을 담은 트랜잭션 추상화 기술을 제공하기 때문임
  • 이를 이용함으로써 애플리케이션에 각 트랜잭션 구현체마다 종속적인 코드를 이용하지 않고도 일관되게 트랜잭션을 처리 가능
  • Spring이 PlatformTransactionManager 최상위 추상 인터페이스를 제공하기 때문에, 이를 이용하여 JDBC 구현체의 경우 DataSourceTxManager를 이용하여 사용이 가능
  • 하지만 이 경우 직접적으로 비즈니스 로직이 Commit, Rollback 등 트랜잭션 작업을 수행해야하기 때문에, 이를 Spring Data JPA가 프록시 패턴을 사용하여 보완

0개의 댓글