미소를뿌리는감자의 코딩

[Spring] @Transactional, 격리 수준, 데드락 본문

강의수강/[Spring]

[Spring] @Transactional, 격리 수준, 데드락

미뿌감 2024. 3. 10. 21:32
728x90

1. 정의

@Transactional 어노테이션은 특정 메소드나 클래스에 적용된다.

해당 범위 내에서 실행되는 코드가 하나의 트랜잭션으로 처리되어야 함을 스프링에게 알려준다.

 

작업을 하나의 작업 단위로 묶어서, 모두 성공하거나 실패하면 모두 취소되도록 보장하는 것을 말한다.

 

2. 특징

  • 데이터 일관성 보장 : 모두 성공적으로 수행되어야 할 때 사용한다. 만약 작업 중 하나라도 실패한다면, 이전 상태로 롤백하여 데이터의 일관성을 유지할 수 있다.
  • 읽기 일관성 유지 : 일관된 데이터를 읽을 수 있도록 보장. -> dirty read를 방지할 수 있다.
  • 자동 롤백 처리 : 자동으로 롤백을 수행. 

 

즉, @Transactional은 데이버 변경 작업을 하나의 논리적은 작업 단위로 묶어서 처리해야할 때, 사용하면 좋다.

주의해야할 점은 class level에 Transactinal을 선언하게 되면, 해당 클래스의 모든 public 메소드에 transaction이 적용된다. 

따라서, 필요한 메소드에만 적용하는 것이 좋다.

 

@Transactional(readonly = true)

읽기만 수행하는 작업일 때는, readonly = true로 설정하여, 데이터를 더 효율적으로 사용할 수 있다.

 

3. 격리 수준

격리 수준은 트랜잭션이 다른 트랜잭션으로부터 독립적으로 실행되는 정도를 의미한다.

DB 시스템에서는 일반적으로 4가지 격리 수준을 제공한다.

  1. READ UNCOMMITTED(읽기 미완료) :
    다른 트랜잭션에 의해 변경되었지만, 아직 커밋되지 않은 데이터를 읽을 수 있다.
    이로 인해서 dirty read (더티 리드)가 발생할 수 있다.
    * dirty read: 아직 commit되지 않은 데이터를 읽는 것
  2. READ COMMITED (읽기 완료)
    커밋된 데이터만 읽을 수 있다. 더티 리드를 방지하지만, 다시 읽을 때 다른 결과가 나타날 수 있는 팬텀 리드논리피팅 문제 발생 가능하다.  읽기 (A) -> 다른 트랜잭션에 의해 commit -> 읽기 (B) 일 때, A와 B의 결과가 다름.
  3. REPEATABLE READ(반복 가능한 읽기) :
    트랜잭션 내에서 한 번 읽은 데이터는 반복해서 읽어도 동일한 데이터를 보장함.
    논리피팅은 방지하지만, 팬텀 리드는 여전히 가능
  4. SERIALIZABLE (직렬화 가능) :
    가장 엄격한 격리 수준으로, 트랜잭션들이 순차적으로 실행되는 것처럼 처리 됨. 모든 종류의 읽기 이상 현상을 방지하지만 성능 저하의 원인이 될 수 있다.

 

* 팬텀 리드: 한 트랜잭션 내에서 같은 쿼리를 두 번 실행 했을 때, 결과가 다른 경우.

                   첫 번째 쿼리 실행 후 다른 트랜잭션이 해당 조건에 맞는 새로운 데이터를 삽입하거나 삭제하고 커밋하면, 동일한 조건의 쿼리

                   를 다시 실행했을 때 새로운 데이터가 포함되거나 빠진 결과를 얻게 됨. 이러한 차이는 업데이트된 데이터가 아님.

                   REPEATABLE READ 격리 수준에서 부분적으로 해결되지만, 완전히 방지하려면 SERIALIZABLE 격리 수준이 필요.

 

* 논리피팅 문제: 한 트랜잭션 내에서 같은 쿼리를 두 번 이상 실행했을 때, 두 쿼리의 결과가 서로 다른 경우 발생

                          다른 트랜잭션이 첫 번째 쿼리와 두 번째 쿼리 사이에 해당 데이터를 수정하거나 업데이트 하기 때문에 생기는 현상.

                          READ COMMITTED 격리 수준에서 해결될 수 있지만, 더 낮은 격리 수준에서는 발생할 위험이 있음.

 

 

4. 전파 동작 ( Propagation Behavior )

한 메소드에서 다르 메소드를 호출할 때, 현재 트랜잭션을 어떻게 처리할 것이지를 정의

  1. REQUIRED : 현재 트랜잭션이 존재하면 이를 재사용. 없다면 새로운 트랜잭션 시작.
  2. REQUIRES_NEW : 항상 새로운 트랜잭션. 현재 트랜잭션이 있다면 일시 중지
  3. SUPPORTS : 현재 트랜잭션이 존재하면 이를 재사용. 없다면 트랜잭션 없이 진행.
  4. NOT_SUPPORTED : 트랜잭션을 사용하지 않음. 현재 트랜잭션이 있다면 일시 중지
  5. MANDATORY : 현재 트랜잭션이 반드시 존재해야 함. 없다면 예외를 발생 시킴.
  6. NEVER: 트랜잭션을 사용하지 않으며, 현재 트랜잭션이 존재하면 예외를 발생 시킴.
  7. NESTEDㅣ 현재 트랜잭션이 존재하면 중첩된 트랜잭션 내에서 실행.

 

5. 데드락 (DeadLock) 

우선 락(Lock)은 트랜잭션이 동시에 같은 데이터에 접근할 때, 데이터의 일관성과 무결성을 보장하기 위해, 특정 데이터 또는 데이터베이스 자원에 대한 접근을 제한하는 것이다.

 

데드락은 이때, 여러 트랜잭션이 서로의 작업 완료를 무한히 기다리는 상태를 의미하낟.

이는 트랜잭션이 서로 다른 자원에 대해 배타 락을 보유하고 있고 각자가 다른 트랜잭션이 보유한 락을 획득하려고 할 때 발생한다.

이는 시스템이 멈춰버리는 상태에 이를 수 있다.

 

즉, 각각의 트랜잭션이 락이 걸린 것을 얻기 위해 기다리는, 무한히 기다리는 상태를 의미한다.

728x90