일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 공룡책
- Server
- 자바
- FCM
- 일상
- modelmapper
- Coputer Science
- Java
- JPA
- 테크쇼
- db
- 인프콘2023
- RequestBody
- Test
- softeer
- Test Doulbe
- ExceptionResolver
- backend
- proxyFactory
- JPQL
- Junit 5
- Test code
- OS
- Service 계층 테스트
- 소프티어
- Spring
- MySQL
- enumSet
- ObjectMapper
- mapstruct
- Today
- Total
공부내용공유
데이터 베이스 트랜잭션과 격리수준 (Transaction and Isolation Level) 본문
데이터 베이스 트랜잭션과 격리수준 (Transaction and Isolation Level)
forfun 2023. 7. 17. 14:49서론
Data 계층 테스트 코드를 작성하기전에 JPA 복습을 하고 있었는데 이전에 공부할때는 그냥 넘어갔던
JPA의 Isolation 부분이 눈에 들어왔다.
고급 데이터 베이스 과목에서 배운 Repetable Read, Phantom Phenomon 등이 보여 흥미로워 복습도 하고 몰랐던 부분을 제대로 공부하기 위해 이 글을 작성하였다.
목차
- 트랜잭션이란?
- DB 트랜잭션 Level 에 따른 차이
- JPA의 트랜잭션 수준
- Optimistic Lock, Pessimistic Lock
트랜잭션이란?
랜잭션, ACID 는 데이터 베이스 과목을 수강하면 정말 많이 나오는 개념이다.
트랜잭션이 무엇일까?
DataBase System concepts 7판에 나온 설명들에 따르면
- 하나의 logical unit을 실행하는 operation의 단위를 transaction이라 한다.
- 트랜잭션은 program execution의 unit이다.
- Begin transaction부터 End transaction 사이의 모든 operation들을 포함한다.
- SQL이나 C++ , java와 같은 프로그래밍 언어에 의해 만들어진다.
라고 나와 있다.
또 그뒤에 트랜잭션의 성질이 나온다.
Atomicity
트랜잭션 도중 무언가 잘못되면 이전에 성공적으로 실행됐던 query문들도 다 같이 취소되야 한다.
즉 성공하면 다같이 성공, 하나라도 실패하면 전부 실패라는 성질이다.
Isolation
이번 포스팅에서 다루는 주요 개념이다.
여러개의 트랜잭션이 DB에 접근했을때 그냥 허용해버리면 한 트랜잭션이 데이터를 수정하는동안 다른 트랜잭션이 지워버리는 등의 문제가 생길 수 있다.
이러한 상황을 예방하기 위해 DB는 Isonlation을 보장해줘야 한다.
Durability
트랜잭션이 성공적으로 마쳐진 경우 이는 데이터베이스에 무조건 반영되야 한다.
Consistency
트랜잭션 실행후 DB의 일관성이 보장되어야 한다 이다.
유니크 제약조건을 지키는 DB에 가까운 일관성부터
유저 A 가 유저 B에게 송금을 하면 송금 전 후 금액은 같아야 하는 비즈니스 로직에 가까운 일관성등을 의미한다.
DB 트랜잭션 Level 에 따른 차이
위에서 얘기했던 트랜잭션의 4가지 성질중 Isolation 을 보장하기 위해 DB는 여러 옵션들을 제공한다.
- Read Uncommited
- Read Commited
- Repaeatable Read
- Serilazation
가 있다.
Read Uncommitted
단어 그대로 다른 트랜잭션에서 수정이 되었지만 commit 이 안된 값을 읽는 수준의 Isolation 이다.
A 트랜잭션이 값을 변경한 후 B 트랜잭션이 그 값을 읽었다. 그 다음 A 트랜잭션에 문제가 생겨 RollBcak을 하게되면 B 트랜잭션이 이전에 읽었던 값은 옳지 못한 값이 된다.
이를 Dirty Read 라고 한다.
Read Committed
오직 Commit 된 데이터만 읽는다. 대부분의 DB 들이 이 Isolation Level을 지원한다.
Oracle, postgreSQL 이 체택하고 있는 방식이다.
만약 A 트랜잭션이 데이터를 수정중이라면 B 트랜잭션은 수정된 데이터가 아닌 UNDO 에서 수정 이전의 데이터를 받는다.
그런데 이때 commit 전에 UNDO 에서 데이터를 읽고
commit 후 한번 더 데이터를 읽게 된다면 데이터의 정합성이 깨진다.
또한 gap-Lock 이 아닌 Record-Lock 만 걸기 때문에 Phantom Record 현상이 발생한다.
Repetable Read
MY-SQL 에서 기본으로 사용하는 방식이다.
각 트랜잭션에 ID 를 부여해서 ID 보다 작은 트랜잭션에서만 데이터를 읽게한다.
UNDO 공간에 데이터를 백업해둔다.
Repeatable Read 의 문제점은 Phantom Read 이다.
다른 트랜잭션이 데이터를 추가하거나 삭제하는 경우 이전과 다른 결과 값이 나와 데이터 정합성이 깨지는 현상을 의미한다.
Phantom Read 에 대해 정확히 이해를 못하고 있었는데 이 블로그를 보고 어떤 개념인지 정확히 알게 되었다.
https://velog.io/@hyunjong96/트랜잭션-격리-수준Isolation-level
https://suhwan.dev/2019/06/09/transaction-isolation-level-and-lock/
일반적인 select 의 경우에는 transaction 시작 이전 데이터만 읽을것이기 때문에 phantom read 가 일어나지 않으나
Select For Update 의 경우 Exclusive Lock 을 거는데 이는 UNDO 영역에 걸지 못하기 때문에 실제 레코드에서 데이터를 가져와 Phantom Read 가 발생하게 된다.
Serializable
이 옵션은 읽기 작업에서도 공유 잠금을 설정하기 때문에 다른 트랜잭션이 조회중인 레코드 변경이 불가하다.
Repeatable Read 로도 못막는 상황을 방지가 가능하나 성능이 떨어지고 데드락이 걸릴 확률이 높아진다.
JPA의 트랜잭션 수준
이렇게 위에서처럼 DB 들이 제공하는 격리수준으로는 해결하지 못하는 문제들이 남아있다.
대표적인 예로는 2번의 갱실 분실문제가 있다.
이러한 문제는 DB에서 제공하는 트랜잭션으로는 해결할 수 없다.
이렇게 되는 경우 취할 수 있는 조치는 3가지이다.
- 1번째 커밋을 받아들이기
- 2번째 커밋을 받아들이기
- 1,2 번째 내용 병합해서 받아들이기
또한 Read Commited 의 격리수준을 제공하는 DB를 사용할때 특정 메소드에서만 격리수준을 높이고 싶을 수 있다.
위 사진과 같은 문제나 특정 메소드 고립성 변경을 JPA 의 비관적 락, 낙관적 락을 사용해 해결할 수 있다.
Optimistic Lock, Pessimistic Lock
낙관적 락
- 트랜잭션이 충돌하지 않는다고 가정하고 락을 건다.
- 자원에 락을 걸어서 선점하지말고 커밋할 때 동시성 문제가 발생하면 그때 처리 하는 방식.
- JPA에서는 자체적으로 제공하는 버전 관리 기능을 사용한다. (hashcode나 timestamp를 이용할 수도 있다.)
- 트랜잭션을 커밋하기 전까지는 충돌 여부를 확인할 수 없다.
비관적 락
- 트랜잭션이 충돌한다고 가정하고 락을 건다.
- DBMS의 락 기능을 사용한다. (ex. SELECT FOR UPDATE)
- 데이터 수정 시 즉시 트랜잭션 충돌여부를 확인할 수 있다.
낙관적 락
@Version
낙관적 락에서 사용하는 @Version 어노테이션을 간단히 설명하면
Entity 에 버전관리용 필드를 추가하고 @Version어노테이션을 붙여준다.
이러한 버전은 엔티티가 수정할때 변경된다.
그래서 아까와 같은 2개의 트랜잭션이 동시에 수정을 해도 한쪽은 버전이 변경된 상태라 업데이트를 하지 못한다. (먼저 commit 한 내용을 체택하는 방식)
낙관적 락 종류
- OPTIMISTIC
- 트랜잭션 시작 시 버전 점검이 수행되고, 트랜잭션 종료 시에도 버전 점검이 수행된다.
- 버전이 다르면 트랜잭션이 롤백된다.
- Read 의 경우도 버전 정보를 커밋할때 확인한다.
- OPTIMISTIC_FORCE_INCREMENT
- 커밋 직전 version 정보를 증가시킨다.
- 관계를 가진 다른 엔터티가 수정되면 버전이 변경된다. (ex. 강의 수강자가 변경되면 강의 버전도 변경된다..)
- READ
- OPTIMISTIC과 동일하다.
- WRITE
- OPTIMSTIC_FORCE_INCREMENT와 동일하다.
- NONE
- 엔터티에 @Version이 적용된 필드가 있으면 낙관적 락을 적용한다.
- 수정 전에는 변경을 알아차릴 수 없다.
- 엔티티를 읽기만 한 경우에는 보장받을 수 없다.
비관적 락
JPA 가 데이터 베이스의 락에 의존하는 방식이다.
주로 쿼리에 Select For Update 를 사용하고 트랜잭션을 시작한다.
비관적 락 종류
- PESSIMISTIC_READ
- 다른 트랜잭션에서 읽기만 가능하다.
- DB 의 shared lock 사용
- 버전을 사용하지 않는다.
- PESSIMISTIC_WRITE
- 다른 트랜잭션에서 읽기, 쓰기를 못한다.
- DB의 Exclusive lock 사용
- 버전을 사용하지 않는다.
- PESSIMISTIC_FORCE_INCREMENT
- 다른 트랜잭션에서 읽기,쓰기를 못한다.
- DB의 Exclusive lock 사용
- 버전을 사용한다.
참고 Ref
트랜잭션
https://velog.io/@hyunjong96/트랜잭션-격리-수준Isolation-level
https://suhwan.dev/2019/06/09/transaction-isolation-level-and-lock/
https://steady-coding.tistory.com/562
JPA Isolation, Lock
https://velog.io/@on5949/JPA-트랜잭션과-락-3.-낙관적-락과-비관적-락
'ComputerScience > DataBase' 카테고리의 다른 글
MongoDB Bulk Ops (feat: insertMany, Bulk Write) 알아보기 (0) | 2024.04.21 |
---|---|
Mongo DB Sharding (feat: replication, partitioning) (2) | 2024.04.05 |
MySQL Bulk Update (feat: temporal table) (0) | 2024.03.21 |
MySQL Order By, Select For Update 최적화 하기 (0) | 2024.03.02 |
MySQL index 설계, 튜닝시 고려사항 (covering, index dive, prefix index) (0) | 2024.02.25 |