JPA

@Transactional이란?

영카이브 2024. 3. 26. 20:33

@Transactional이란?

  • @Transactional은 스프링 프레임워크에서 제공하는 어노테이션으로, 트랜잭션을 관리하기 위해 사용된다.
  • 메서드나 클래스에 붙여주며 해당 메서드나 클래스의 실행이 하나의 트랜잭션 단위로 처리된다.
  • 이러한 작업들은 모두 성공하거나 모두 실패해야 한다.
  • 트랜잭션의 ACID 속성을 충족시키기 위해 일반적으로 "원자성(Atomicity)", "일관성(Consistency)", "고립성(Isolation)", "지속성(Durability)"을 보장해야 한다.
  • @Transactional 어노테이션을 사용하면 스프링은 해당 메서드나 클래스를 실행할 때 트랜잭션을 시작하고, 메서드 또는 클래스의 실행이 성공하면 트랜잭션을 커밋(commit)하여 변경 사항을 영구반영한다. 만약 실행 중에 예외가 발생하면 트랜잭션을 롤백(rollback)하여 이전 상태로 되돌린다.

 

이를 통해 데이터베이스에서 일어나는 여러 작업들을 안전하게 묶어서 처리할 수 있으며, 데이터 일관성을 유지하고 문제가 발생해도 데이터의 무결성을 보장할 수 있다.

 

 

 

@Tranactional의 역할

  1. 일관성 유지: 회원가입 프로세스는 여러 단계로 이루어질 수 있다. 예를 들어, 사용자 정보를 저장하는 동안 예기치 않은 오류가 발생하면 일부 데이터가 데이터베이스에만 저장되고 일부는 저장되지 않을 수 있다. 이러한 @Transactional을 사용하여 모든 데이터베이스 작업이 하나의 트랜잭션으로 묶이도록 하여 일관성을 유지할 수 있다.
  2. 롤백 기능: 회원가입 프로세스 중 하나의 단계에서 오류가 발생하면 해당 트랜잭션은 롤백되어 이전 상태로 복구된다. 이를 통해 데이터베이스는 일관된 상태를 유지할 수 있다. 예를 들어, 사용자 정보를 저장하는 동안 암호화된 패스워드를 저장하는 과정에서 오류가 발생하면, 트랜잭션은 롤백되어 사용자 정보와 패스워드 모두 저장되지 않는다.
  3. 동시성 문제 방지: 여러 사용자가 동시에 회원가입을 시도할 수 있다. 이때 각각의 회원가입 작업은 별도의 트랜잭션으로 처리되어야 한다. @Transactional을 사용하면 각 회원가입 요청이 별도의 트랜잭션으로 처리되어 데이터베이스의 일관성과 동시성을 보장할 수 있다.

 

 

@Transactional의 작동 원리와 흐름

 

@Transactional이 클래스 또는 메서드에 붙을 때, 스프링 프레임워크는 해당 클래스 또는 메서드를 호출할 때 트랜잭션 기능을 제공하기 위해 프록시를 생성한다 .프록시 객체원래 객체를 감싸고 있는 객체이며 원래 객체와 타입은 동일하다.  

 

프록시 패턴은 디자인 패턴 중 하나로, 프록시 객체가  원래 객체를 감싸서 추가적인 연산을 수행하도록 강제하는 방법이다. 트랜잭션의 경우, 트랜잭션의 시작과 연산 종료시의 커밋 과정이 필요하므로, 프록시를 생성해 해당 메서드의 앞뒤에 트랜잭션의 시작과 끝을 추가하는 것이다.

 

 

  1. 클라이언트가 "/hello" 엔드포인트로 HTTP 요청을 보낸다.
  2. 이 요청을 받은 HelloController가 해당 요청을 처리한다.
  3. HelloController는 HelloService의 메서드를 호출하여 비즈니스 로직을 수행한다. HelloService 내에서는 트랜잭션 AOP에 의해 감싸진 메서드가 실행되고 이 때 트랜잭션이 시작되며 영속성 컨텍스트가 생성된다.
  4. HelloService 내에서는 Repository1과 Repository2를 사용하여 데이터베이스와 상호작용한다.
  5. 비즈니스 로직이 완료되면 HelloService의 메서드 실행이 종료된다. 이때 트랜잭션 AOP에 의해 트랜잭션이 종료되어 트AOP가 트랜잭션을 커밋할 경우 영속성 컨텍스트는 flush되면서 변경 사항이 데이터베이스에 반영된다. 이후 영속성 컨텍스트가 종료된다.

 

*영속성 컨텍스트 : 데이터베이스와 애플리케이션 사이에 존재하는 일종의 작업 영역이며, 엔티티(Entity) 객체의 상태를 추적하고 관리하는 데 사용된다. 주로 ORM 프레임워크에서 사용되며, 엔티티와 데이터베이스 레코드 간의 매핑 작업을 관리한다.

 

 

@Transactional의 격리 수준, 전파 방식 및 롤백 조건

 

 

격리 수준(Isolation Level) : 격리 수준은 트랜잭션에서 발생하는 데이터의 일관성과 관련이 있다. 

 

@Transactional 어노테이션은 기본적으로 DEFAULT 격리 수준을 사용한다.

  1. DEFAULT: 데이터베이스의 기본 격리 수준을 사용
  2. READ_UNCOMMITTED: 커밋되지 않은 다른 트랜잭션의 데이터를 읽을 수 있음.
  3. READ_COMMITTED: 커밋된 다른 트랜잭션의 데이터만 읽을 수 있음.
  4. REPEATABLE_READ: 같은 쿼리를 실행해도 항상 같은 결과가 나오도록 보장
  5. SERIALIZABLE: 가장 엄격한 격리 수준으로, 트랜잭션이 완료될 때까지 다른 트랜잭션은 해당 데이터에 접근할 수 없음.

전파 방식(Propagation) : 트랜잭션의 전파 방식은 이미 실행 중인 트랜잭션이 있을 때 새로운 트랜잭션이 시작되는 방식을 정의한다.

  1. REQUIRED: 이미 실행 중인 트랜잭션이 있으면 해당 트랜잭션에 참여하고, 그렇지 않으면 새로운 트랜잭션을 시작한다.
  2. REQUIRES_NEW: 항상 새로운 트랜잭션을 시작한다. 이미 실행 중인 트랜잭션이 있으면 일시 중단된다.
  3. SUPPORTS: 이미 실행 중인 트랜잭션이 있으면 해당 트랜잭션에 참여하고, 그렇지 않으면 트랜잭션 없이 메서드를 실행한다.
  4. NOT_SUPPORTED: 이미 실행 중인 트랜잭션이 있으면 해당 트랜잭션을 일시 중단하고, 트랜잭션 없이 메서드를 실행한다.
  5. NEVER: 이미 실행 중인 트랜잭션이 있으면 예외를 발생시킨다.

롤백 조건(When Does It Rollback?) 

  1. 예외 발생: 트랜잭션 내에서 예외가 발생하면 롤백된다.
  2. rollbackFor 속성: 특정 예외가 발생할 경우 롤백할 수 있도록 지정한다.
  3. noRollbackFor 속성: 특정 예외가 발생해도 롤백하지 않도록 지정한다.
  4. readOnly 속성: 읽기 전용 트랜잭션일 경우 롤백되지 않는다.
  5. @Transactional(rollbackFor = Exception.class)와 같이 rollbackFor 속성을 명시하면 모든 예외에 대해 롤백된다.

@Transactional 어노테이션을 사용할 때 이러한 격리 수준, 전파 방식, 그리고 롤백 조건을 고려하여 트랜잭션을 적절하게 설정하는 것이 중요하다. 이를 통해 데이터 일관성과 안정성을 보장할 수 있다. 

 

 

 

 

참고 자료 출처 :

https://kafcamus.tistory.com/30

https://velog.io/@max9106/Spring-%ED%94%84%EB%A1%9D%EC%8B%9C-AOP-xwk5zy57ee