skarltjr / Memory_Write_Record

나의 모든 학습 기록
0 stars 0 forks source link

DB 트랜잭션 조금 알아보기 #117

Open skarltjr opened 1 year ago

skarltjr commented 1 year ago

주제 : 원자성

트랜잭션이란

데이터베이스의 상태를 변화시키는 동작의 단위
- 여러 읽기/쓰기를 논리적으로 하나로 묶음
- 트랜잭션 시작 -> 여러 쿼리 실행 -> 커밋 or 롤백
- all or nothing

트랜잭션 범위는 ⭐️커넥션 기준

그럼 우리가 여러 트랜잭션을 단일 트랜잭션으로 묶고싶다면?


## 트랜잭션 전파
- 여러 매서드에서 수행되는 트랜잭션을 단일 트랜잭션으로 묶고싶다

스프링의 @Transactional은 기본적으로 전파 레벨이 Required -> 이미 시작된 트랜잭션이 있다면 참여하고 없다면 새로 생성하여 시작


## 트랜잭션과 외부 연동
- 트랜잭션 내부에 외부 서비스등이 연동되어있다면 롤백 처리에 주의해야한다
- <img width="906" alt="스크린샷 2022-07-24 오후 9 16 18" src="https://user-images.githubusercontent.com/62214428/180646535-a403c23c-0860-4440-9650-3f1e2c41edae.png">

왼쪽 그림의 경우 외부api 호출에 실패하여 롤백처리 -> 큰 문제가 없다 -> 외부 서비스 호출이 실패했기에 외부 서비스에 영향을 주지 않고 현재 내가 수행한 명령어에 대해서 롤백처리만 하면 ok

-> 물론 왼쪽 그림도 문제가 없는건 아니다 -> 실제 외부 서비스가 잘 호출되었는데 그 응답을 받을 때 네트워크 문제로 응답만 못받은경우 롤백이 발생한다. -> 즉 이 경우는 외부 서비스가 잘 동작했음에도 롤백시키는 경우

오른쪽그림의 경우 문제가 될 수 있다 -> 이미 외부 서비스를 호출한 상태 / ex) 외부 결제 시스템을 통해 결제를 한 상태 -> 롤백을 수행할거면 외부 서비스에도 상태를 변화시킬 행동(복구)을 추가로 취해야한다


## two phase commit (2pc)

두 개 이상의 자원 (ex. db, mq)을 한 트랜잭션으로 처리

예를 들어 두 개의 db를 하나의 트랜잭션으로 묶는다던가, db-mq를 하나의 트랜잭션으로 묶는다던가

그런데! 거의 사용하지 않는다.

skarltjr commented 1 year ago

주제 : 동시성, 격리

Race condition

여러 클라이언트에서 동시에 자원에 접근하여 활용하려고 할 때 문제가 발생할 수 있다.
가장 쉬운 방법은 트랜잭션을 줄세워 차례대로 수행시키는거지만 성능상 매우 안좋다

Isolation

따라서 트랜잭션을 서로 격리해서 다른 트랜잭션이 영향을 주지 못하게한다

Read uncommitted - 사실상 거의 사용하지 않는다
Read committed
repeatable read
serializable

Level 0 - read uncommitted

dirty read
올바르게 처리되지 않은 데이터를 다른 트랜잭션에서 참조하는 경우 문제가 발생할 수 있다

dirty write
아직 처리되지 않은 데이터를 덮어쓰는 경우도 문제가 될 수 있다.

Level 1 - read committed

1. 커밋된 데이터만 읽기
- 커밋된 값과 트랜잭션 진행중인 값을 따로 보관 
2. 커밋된 데이터만 덮어쓰기
- 행 단위 잠금 사용
- 같은 데이터를 수정하는 트랜잭션이 존재한다면 끝날때까지 대기 후 그 다음에 데이터를 수정하도록한다
그러나 여전히 문제는 존재
non-repeatable read 문제 발생

Level 2 - Repeatable Read

레벨1의 문제는 트랜잭션 진행동안 데이터가 변경되는 문제
-> 레벨2는 트랜잭션동안 같은 데이터를 읽게 한다

즉 Repeatable Read는 트랜잭션 진행동안 데이터가 변경되더라도 같은 데이터를 읽도록 해준다
- 읽는 시점에 특정 버전에 해당하는 데이터만 읽음
level2에서는 같은 데이터를 쓸 때 변경이 유실되는 경우를 막기위한 방법이 여러가지 존재
 1. db가 제공하는 원자적 연산
ex ) update article set readCount = readCount+1 where id =. 

2. 명시적 잠금
ex) select ... for update
-> 이 경우 조회 시 락을 걸고 변경 후 락을 해제
-> 즉 읽는동안 다른 트랜잭션에서 해당 데이터 읽기 및 수정 불가

⭐️서로 다른 데이터를 다루지만 논리적으로 race condition인 경우는?

결국 이 문제