Spring Projcect/날씨 일기 프로젝트

Chapter 06. Spring Transaction(스프링 트랜잭션)

계란💕 2022. 8. 31. 21:29

6.1 트랜잭션(Transaction)이란?

 

Transaction(트랜잭션)

  • 데이터베이스의 상태를 변화시키기 위해 수행하는 작업 단위를 '트랜잭션'이라고 한다.
    • ex) 오늘의 날씨 데이터를 가져와서 일기 정보를 DB에 저장하기까지의 작업 단위를 트랜잭션이라고 볼 수 있다.

 

  • 트랜잭션의 속성
    • 원자성(Atomicity) - 트랜잭션이 데이터베이스에 모두 반영되거나 또는 반영되지 않거나 반드시 둘 중 하나여야만 하다. 
    • 일관성(Consistency) - 트랜잭션의 작업 처리 결과는 언제나 일관적이어야한다.
    • 독립성(Isolation) - 여러 트랜잭션들이 독립적으로 수행되어야 한다.
    • 지속성(Durablity) - 트랜잭션이 성공적으로 완료된 경우 변화된 상태가 지속적으로 반영되어야한다.

 

  • 트랜잭션의 연산 - 원자성 만족시키기 위한 방법
    • 커밋(Commit) - 트랜잭션이 성공적으로 끝났을 때, 모든 수정 사항을 반영하기 위해 커밋한다.
    • 롤백(Rollback) - 어떤 예외 사항이나 문제가 발생하는 경우에 롤백한다. 트랜잭션 작업 하기 전의 데이터베이스 상태로 돌아간다. 

 

 

 

여러 트랜잭션이 경쟁하면 생기는 문제는? (면접 빈출)

  1. Dirty Read: 트랜잭션A는 다이어리 테이블의 세 번째 row를 수정하고 있다. 트랜잭션B는 다이어리 테이블의 세 번째 row를 조회하려고 하는 경우
  2. Non-Repeatable Read(일관성을 헤치는 경우): 트랜잭션A (세 번째 row를 조회하는 중) vs 트랜잭션B(세 번째 row 수정 후 커밋)
  3. Phantom Read: 트랜잭션A (첫 번째 ~ 네 번째 row를 조회하는 중) vs 트랜잭션B(세 번째 row 수정 후 커밋)
    • 2) 3) 의 차이는? 2: 특정 값에 대해 경쟁했을 때 문제, 3: 특정 범위 내에서 경쟁했을 때 문제

 

 

 

6.2 스프링에서의 트랜잭션(Transaction)

 

 스프링 트랜잭션 세부 설정

  • @Transaction(선언적 트랜잭션) - 클래스나 메서드 위에 어노테이션을 추가한다. 
    • @Transaction이 붙은 클래스나 메서드에 대해 트랜잭션 기능이 적용된 프록시 객체를 생성한다.
    • PlatformTransactionManager가 트랜잭션을 시작하고 관리한다. 트랜잭션에 성공했는지 아닌지 판단해서 커밋 또는 롤백하도록 한다.

 

cf) 프록시 서버(proxy server): 클라이안트가 자신을 통해 다른 네트워크 서비스에 간접적으로 접속할 수 있게 해주는 컴퓨터 시스템이나 응용프로그램을 가리킨다. 

  • 서버와 클라이언트 사이에서 중계기로서 대리로 통신을 수행하는 것을 가리켜 '프록시', 중계 기능을 하는 것은 프록시 서버라고 부른다.

 

  • 1. Isoaltion(격리 수준) - 중요!
    • Isoaltion이란 트랜잭션에서 일관성이 없는 데이터를 허용하는 수준을 말한다.
    • Ex)  @Transaction(isolation=Isolation.DEFAULT)
      • DEFAULT: 가장 기본적으로 쓰인다. (금융업이나 정확성이 중요한 경우에는 특정 트랜잭션에 대해서   DEFAULT 가 아닌  REPEATABLE_READ이나 SERIALIZABLE로 설정한다.)
      • READ_UNCOMMITTED: 커밋 전 이더라도 read 가능 - Dirty Read 발생 가능
      • READ_COMMITTED: 커밋 후에야 read 가능 - Dirty Read 방지
      • REPEATABLE_READ: 트랜잭션 전체가 완료될 때까지 SELECT문이 사용한 부분에 대해 shared lock을 건다. 앞서 어떤 트랜잭션이 read중이면  트랜잭션이 종료되기 전까지 다른 트랜잭션이 와서 같은 데이터를 처리할 수 없다. - Non-Repeatable Read & Dirty Read 방지
      • SERIALIZABLE: 트랜잭션이 완료될 때까지 사용중인 모든 데이터에 대해 shared lock을 건다. - Phantom Read 방지, 일관성  & 동시성 유지, (가장 빡빡한 조건)

 

  • 2.Propagation(전파 수준)
    • 트랜잭션 동작 도중에 다른 트랜잭션을 호출하는 상황을 말한다.
    • 트랜잭션을 시작하거나 기존 트랜잭션에 참여하는 방법에 대해 결정하는 속성값이다.
    • Ex)
      • REQUIRED: (디폴트) 부모 트랜잭션 안에서 자식 트랜잭션까지 함께 실행된다. 부모 트랜잭션이 없는 경우에만 새로운 트랜잭션을 실행한다.
      • SUPPORT: 이미 시작된 트랜잭션이 있으면 참여하고  없으면 트랜잭션 없이 진행한다.
      • REQUIRES_NEW: 부모 트랜잭션 안에서 함수가 실행되는 경우이더라도 자식을 위한 새로운 트랜잭션 만들어서 동작한다.
      • NESTED: 이미 시작된 트랜잭션이 있는 경우에 중첩해서 트랜잭션을 하나 더 만들어서 실행하는 경우이다. 중첩된 트랜잭션은 부모 트랜잭션이 커밋 / 롤백이 됐는지 영향 받지만, 반면에 중첩된 트랜잭션의 커밋 / 롤백 여부는 부모 트랜잭션에 영향을 주지 않는다.
        • NESTED의 ex)  일기 작성 관련해서 로그를 DB에 저장하는 상황
          • 로그 저장 실패하는 경우 일기 작성까지 롤백되면 안된다.
          • 일기 작성이 실패한다면 로그 작성까지 롤백되어야한다.

 

  • 3. readOnly 속성
    • 트랜잭션을 읽기 전용 속성으로 지정한다.
    • @Transactional(readOnly = true)
    • false가 기본값이다.
    • readOnly를 이용하면 트랜잭션의 성능이 빨라진다. 조회만 하는 경우는 웬만하면 붙여서 성능을 높이도록 한다.

 

  • 4. 트랜잭션 롤백 예외
    • 예외 발생했을 때, 트랜잭션 롤백시킬 경우를 설정한다.
      • Ex)
      • @Transactional(rollbackFor= Exception.class): 어떤 예외가 발생하면 롤백된다.
      • @Transactional(noRollbackFor= Exception.class): 어떤 예외가 발생해도 롤백 되지 않고 커밋된다.

 

  • 5. Timeout 속성
    • 일정 시간 내에 트랜잭션을 끝내지 못하면 롤백한다.
    • 격리 수준이 빡빡한 경우 속도가 느리면 timeout 속성도 함께 쓰면 좋다.

 

 

 

6.3 트랜잭션(Transaction)이란?

 

트랜잭션을 코드에 반영하기

  • Service에 트랜잭션을 많이 붙인다.
  • WeatherApplication위에 @EnableTransactionManagement을 붙이면  프로젝트 안에서 트랜잭션이 활성화된다.
  • Service에도 @Transactional(readOnly = true)을 붙인다. 그럼 Service 각 메서드가 트랜잭션으로 동작한다.
@Transactional(readOnly = true)

 

 

  Ex) 클래스와 메서드에 readOnly가 다르게 붙으면?

  • 지금 Service클래스에 트랜잭션 애너테이션 readOnly = true가 붙은 상태에서 Service의 하위 메서드 createDiary()에  다음과 같이 어노테이션을 붙인다.
@Transactional(readOnly = false)

 

http://localhost:8080/create/diary?date=2022-08-01

 - 일기 내용(I want to learn spring boot! AM 12:35)을 적고 위 링크를 이용해서 POST 한 다음,

 

http://localhost:8080/read/diary?date=2022-08-01

  - GET

 

  Note) 실행 결과

    - 아래 다이어리에 새로운 text가 나온다.

    - 데이터베이스에 값이 잘 들어가고 아래의 쿼리문이 실행된 걸 알 수 있다.

 

  cf)

    - readOnly = false가 기본값이라서 다음과 같은 알림을 볼 수 있다.

 

 

 

  Ex) 트랜잭션 예시

  • createDiary() - 격리 수준 지정 (가장 빡빡한 serializable)
<hide/>
@Transactional(isolation = Isolation.SERIALIZABLE)
public List<Diary> readDiary(LocalDate date){

}

 

  • test 코드에 @Transactional을 붙이면 변경 사항을 커밋하지 않는다. 모두 롤백 처리해버린다.
    • test 코드 안에 데이터베이스 변경 내용이 있더라도 실제 데이터베이스에 영향을 주지 않도록 한다. 
<hide/>
@SpringBootTest
@Transactional
class JpaMemoRepositoryTest {
...
}

 

 

출처 - 제로베이스 백엔드 스쿨 (김조현 강사님)

https://zero-base.co.kr/

 

제로베이스 - 누구나 취업하는 가장 합리적인 취업 스쿨

코딩 부트 캠프 개발자, 데이터 사이언티스트, 마케터, PM, 디자이너 등 제대로 공부하고 확실하게 취업하세요. 당신의 삶의 전환점이 될 제로베이스 스쿨입니다.

zero-base.co.kr