나의 삽질일기/JPA

[jpa] @Transactional 이 뭔데?

2023. 5. 16. 16:45
목차
  1. 1. "트랜잭션" 이란?
  2. 2. @Transactional
  3. 3. 스프링에서 @Transactional 사용하기
728x90

1. "트랜잭션" 이란?

데이터베이스 관리 시스템 또는 유사한 시스템에서 상호작용의 단위이다.
여기서 유사한 시스템이란 트랜잭션이 성공과 실패가 분명하고 상호 독립적이며, 일관되고 믿을 수 있는 시스템을 의미한다.
데이터의 정합성을 보장하기 위해 고안된 방법이다.
트랜잭션을 사용함으로 오류로부터 복구를 허용하고, 데이터베이스를 일관성 있게 유지하는 안정적인 작업 단위를 제공하며,
동시 접근하는 여러 프로그램 간 격리를 제공한다.

 

1-1. 트랜잭션 ACID

이론적으로 데이터베이스 시스템은 각각의 트랜잭션에 대해 원자성(Atomicity), 일관성(Consistency), 독립성(Isolation), 영구성(Durability)을 보장한다. 이 성질을 첫 글자를 따 ACID라 부른다.
  • 원자성 (Atomicity) : 트랜잭션이 완전히 성공하거나, 완전히 실패하는 단일 단위로 처리되도록 보장하는 능력, 중간단계까지 실행되고 실패하는 것이 없도록 하는 것이다.
  • 일관성 (Consistenty) : 각 데이터 트랜잭션이 데이터베이스를 일관성 있는 상태에서 일관성 있는 상태로 이동해야 함을 의미한다. 즉 트랜잭션이 성공적으로 완료하면 언제나 동일한 데이터베이스 상태로 유지하는 것을 의미한다.
  • 독립성 (Isolation) : 트랜잭션을 수행 시 다른 트랜잭션의 연산 작업이 끼어들지 못하도록 보장하는 것을 의미한다. 이것은 트랜잭션. 밖에 있는 어떤 연산도 중간 단계의 데이터를 볼 수 없음을 의미한다. 여러 트랜잭션이 동시에 발생하는 경우 최종 상태는 트랜잭션이 개별적으로 발생한 것과 같아야 한다. 즉, 데이터베이스는 스트레스 테스트를 통과해야 한다. 즉, 과부하로 인해 잘못된 데이터베이스. 트랜잭션이 발생하지 않아야 한다.
  • 영구성 (Durability) : 성공적으로 수행된 트랜잭션은 영원히 반영(기록)되어야 함을 의미한다. 트랜잭션은 로그에 모든 것이 저장된 후에만 commit 상태로 간주될 수 있다. 데이터베이스 내의 데이터는 트랜잭션의 결과로만 변경되어야 하며 외부 영향에 의해 변경될 수 없어야 한다. 예를 들어 소프트웨어 업데이트로 인해 데이터가 실수로 변경되거나 삭제되지 않아야 한다.

 

1-2. 트랜잭션 과정

  1. 트랜잭션 시작
  2. 비즈니스 로직 실행 ( 여러 쿼리들이 실행되지만 ,DB에 갱신되진 않는다. )
  3. 트랜잭션 커밋 ( 트랜잭션이 성공적으로 끝나면, DB에 내용이 갱신된다. )

 

1-3. 결론

특정 실행 단위에서 오류가 발생하면, 즉시 결과를 롤백(rollback) 해주는 기능이다.

 

 

2. @Transactional

  • 소스코드에서 직접 트랜잭션을 구현하지 않고, Spring AOP를 이용해 비즈니스 로직에서 완전히 분리하는 방식이다.
  • 다음과 같이 비즈니스 로직을 포함하는 메서드를 @Transactional 애노테이션으로 감싸는 방식으로 사용한다.
@Transactional
public void saveItem(Item item) {
    // Business Logics
}

 

2-1. 격리 수준 (Isolation Level)

@Transactional(isolation = Isolation.DEFAULT)
  • Isolation.DEFAULT : 데이터 베이스에서 설정된 기본 격리 수준을 따른다.
  • Isolation.READ_UNCOMMITED : 트랜잭션이 아직 커밋되지 않은 데이터를 읽을 수 있다. (Level 0)
  • Isolation.READ_COMMITED : Dirty Read 를 방지하기 위해 Commit 된 데이터만 읽을 수 있다. (Level 1)
  • Isolation.REPEATEABLE_READ : 트랜잭션이 완료될 때까지 조회한 모든 데이터에 shared lock이 걸리므로 트랜잭션이 종료될 때까지 다른 트랜잭션은 그 영역에 해당하는 데이터를 수정할 수 없다. (Level 2)
  • Isolation.SERIALIZABLE : 가장 엄격한 트랜잭션 격리 수준으로, 완벽한 읽기 일관성 모드를 제공합니다. 이 격리 수준에서는 PHANTOM READ 상태가 발생하지 않지만 동시성 처리 성능이 급격히 떨어질 수 있다. (Level 3)
격리 수준이 높아질 수록 데이터 무결성을 유지할 수 있지만, 모든 트랜잭션을 순차적으로 처리하며 동시성이 떨어지고 비용이 높아진다.
따라서, 상황에 맞게 적당한 격리 수준을 사용하는 것이 좋다

 

2.2. 전파 옵션 (Propagination)

@Transactional(propagation = Propagation.REQUIRED)
  • Propagination.REQUIRED : 이미 시작된 트랜잭션이 있으면 참여하고, 없으면 새로운 트랜잭션을 시작한다. (디폴트 속성)
  • Propagination.SUPPORTS : 이미 시작된 트랜잭션이 있으면 참여하고, 없으면 트랜잭션 없이 처리한다..
  • Propagination.REQUIRED_NEW : 항상 새로운 트랜잭션을 시작합니다. 이미 진행중인 트랜잭션이 있다면 잠시 보류시킨다.
  • Propagination.MANDATORY : 이미 시작된 트랜잭션이 있으면 참여하고, 없으면 새로운 트랜색션을 시작하는 대신 예외를 발생시킵니다. 혼자서는 독립적으로 수행되면 안되는 경우에 사용된다.
  • Propagination.NOT_SUPPORTED : 트랜잭션을 사용하지 않고 처리하도록 합니다. 이미 진행중인 트랜잭션이 있다면 잠시 보류시킨다.
  • Propagination.NEVER : 트랜잭션을 사용하지 않도록 강제시킵니다. 이미 진행중인 트랜잭션 또한 허용하지 않으며, 있다면 예외를 발생시킨다.
  • Propagination.NESTED : 이미 실행중인 트랜잭션이 있다면 중첩하여 트랜잭션을 진행합니다. 부모 트랜잭션은 중첩 트랜잭션에 영향을 주지만 중첩 트랜잭션은 부모 트랜잭션에 영향을 주지 않는다.

 

2.3. 읽기 전용 (Read Only)

@Transactional(readOnly = true)
  • JPA의 경우, 해당 옵션을 true 로 설정하게 되면 트랜잭션이 커밋되어도 영속성 컨텍스트를 플러시하지 않는다. 플러시할 때 수행되는 엔티티의 스냅샷 비교 로직이 수행되지 않으므로 성능을 향상 시킬 수 있다.
  • 기본값은 false로, true로 설정할 시 insert, update, delete 를 실행하면 예외를 던지게 된다.

 

3.4. 예외 무시 (No Rollback For)

@Transactional(noRollbackFor = Exception.class)

noRollbackFor 에 할당한 예외에 대해서 롤백을 무시할 수 있다.

 

2.5. 예외 추가 (Rollback For)

@Transactional(rollbackFor = Exception.class)

rollbackFor 에 할당한 예외에 대해서 항상 롤백을 한다.

 

3. 스프링에서 @Transactional 사용하기

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class ItemService {

    private final ItemRepository itemRepository;

    @Transactional
    public void saveItem(Item item) {
        itemRepository.save(item);
    }

    public List<Item> findItems() {
        return itemRepository.findAll();
    }

}

3.1. 비즈니스 로직과의 결합

트랜잭션을 중구난방으로 적용하는 것은 좋지 않다. 대신 특정 계층의 경계를 트랜잭션 경계와 일치시키는 것이 좋은데, 일반적으로 비지니스 로직을 담고 있는 서비스 계층의 메소드와 결합 시키는 것이 좋다. 왜냐하면 데이터 저장 계층으로부터 읽어온 데이터를 사용하고 변경하는 등의 작업을 하는 곳이 서비스 계층이기 때문이다. 위와 같이 클래스 레벨에 트랜잭션 어노테이션을 붙여주면 메소드까지 적용이 된다.

서비스 계층을 트랜잭션의 시작과 종료 경계로 정했다면, 테스트와 같은 특별한 이유가 아니고는 다른 계층이나 모듈에서 DAO에 직접 접근하는 것은 차단해야 한다. 트랜잭션은 보통 서비스 계층의 메소드 조합을 통해 만들어지기 때문에 DAO가 제공하는 주요 기능은 서비스 계층에 위임 메소드를 만들어둘 필요가 있다. 그리고 가능하면 다른 모듈의 DAO에 접근할 때는 서비스 계층을 거치도록 하는 것이 바람직하다.

 

3.2. 읽기 전용 트랜잭션의 공통화

클래스 레벨에는 공통적으로 적용되는 읽기전용 트랜잭션 어노테이션을 선언하고, 추가나 삭제 또는 수정이 있는 작업에는 쓰기가 가능하도록 별도로 @Transacional 어노테이션을 메소드에 선언하는 것이 좋다. 이를 체감하기는 힘들겠지만 약간의 성능적인 이점을 얻을 수 있다.

 


참고문헌

https://velog.io/@betterfuture4/Spring-Transactional-총정리

https://velog.io/@kdhyo/JavaTransactional-Annotation-알고-쓰자-26her30h

https://mangkyu.tistory.com/170

 


https://github.com/wwan13

 

wwan13 - Overview

😜. wwan13 has 32 repositories available. Follow their code on GitHub.

github.com

 

728x90
저작자표시 (새창열림)
  1. 1. "트랜잭션" 이란?
  2. 2. @Transactional
  3. 3. 스프링에서 @Transactional 사용하기
'나의 삽질일기/JPA' 카테고리의 다른 글
  • [jpa] hibernate proxy
  • [jpa] 즉시로딩 (Eager) 과 지연로딩 (Lazy)
  • [jpa] 변경 감지와 병합
  • [jpa] 영속성 컨텍스트가 뭔데?
wwan13
wwan13
내가 보려고 정리해둔 블로그
taewan.log내가 보려고 정리해둔 블로그
wwan13
taewan.log
wwan13
전체
오늘
어제
  • ALL (35)
    • 회고 (1)
    • 나의 삽질일기 (34)
      • Spring (12)
      • JPA (6)
      • Algorithm (4)
      • Cleancode & Refactoring (8)
      • Infra (4)
hELLO · Designed By 정상우.
wwan13
[jpa] @Transactional 이 뭔데?
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.