Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 143 additions & 0 deletions 4장_데이터베이스/트랜잭션과_무결성.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# 4장. 데이터베이스

Created: 2022년 11월 7일 오후 11:57
Last Edited Time: 2022년 11월 11일 오전 12:08

# 4장 데이터베이스

## 4.3 트랜잭션과 무결성

트랜잭션은 DB에서 하나의 논리적 기능을 수행하기 위한 작업의 단위를 말하며

DB에 접근하는 방법은 쿼리이므로, 여러 쿼리를 하나로 묶는 단위를 말한다.

### 트랜잭션의 특성

> 원자성

트랜잭션과 관련된 일이 모두 수행되었거나 되지 않았거나를 보장하는 특징

All or Nothing 의 개념으로 작업 단위의 일부분만 실행하지 않는다는 것

트랜잭션 단위로 여러 로직을 묶을 때 외부 API를 호출하는 것이 있으면 안된다.

있다면, 롤백을 해야할 경우에 어떻게 해야할 것인지에 대한 해결 방법이 있어야하고

트랜잭션 전파를 신경써서 관리해야 한다.

### 커밋, 롤백

커밋은 여러 쿼리가 성공적으로 처리되었다고 확정하는 명령어

트랜잭션 단위로 수행되며 변경된 내용이 모두 영구적으로 저장되는 것을 말한다.

반영을 하는 도중에 에러가 나거나 다른 이슈때문에 이전으로 돌려야 한다면? 할때 사용하는 것이 바로 롤백이다.

한 트랜잭션 과정을 일어나기 전으로 돌리는 역할을 수행한다.

이 두가지 기능덕에 데이터의 무결성이 보장되고, 변경 전에 변경사항을 쉽게 확인이 가능하며 해당 작업을 그룹화할 수 있다.

### 트랜잭션 전파 (Transaction Propagation)

트랜잭션을 수행할 때는 커넥션 단위로 수행하기 때문에 커넥션 객체를 넘겨 수행한다.

그렇지만 매번 넘겨주기는 힘들기 때문에 여러 트랜잭션 관련 메소드의 호출을 하나의 트랜잭션에 묶이도록 하는것이 바로 트랜잭션 전파이다.

스프링에서는 대표적으로 Service Layer에서 `@Transactional` 을 통해 해당 역할을 수행한다.

스프링의 트랜잭션 전파 전략은 [스프링 Docs](https://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/transaction.html#tx-propagation) 에서 확인이 가능하다.

```java
@Service
@Transactional
public record DemoService(UserRepository userRepository) {

@Transactional(readOnly=true)
public User findOne(final Long userId) {
return userRepository.findById(userId).orElseThrow();
}
}
```

### 일관성

허용된 방식으로만 데이터를 변경해야 하는 것을 의미함.

DB에 기록된 모든 데이터는 여러가지 조건, 규칙에 따라 유효함을 가져야 한다.

### 격리성

트랜잭션 수행 시 서로 끼어들지 못함.

> 트랜잭션 격리수준

| 격리수준 | 특징 | 나타나는 현상 |
|---------------------------------------------|--------------------------------------------------------------------------|---------|
| READ_UNCOMMITTED | 트랜잭션이 실행 중일때, 다른 트랜잭션에 의해 수정이 되었지만 커밋이 되지 않았는데도 그 데이터를 읽을 수 있는 경우가 존재한다. | 더티리드 |
| READ_COMMITTED | 가장 많이 사용되는 격리수준 | |
| READ_UNCOMMITTED와는 다르게 커밋하지 않은 정보는 읽을 수 없음. | not-repeatable read | |
| REPEATABLE_READ | MySQL 8.0 의 기본 격리 수준 | 팬텀리드 |
| SERIALIZABLE | 여러 트랜잭션이 동시에 같은 행에 접근할 수 없음. | |

나타나는 현상자체를 전부 통제함.
교착상태(Deadlock)이 가장 일어날 확률이 높다. | X |

> Dirty Read

반복가능하지 않은 조회(Non-Repeatable Read)와 유사하며, 한 트랜잭션이 실행중일 때 다른 트랜잭션에 의해 수정되었지만 아직 **커밋되지 않은** 행의 데이터를 읽을 수 있는 경우 발생함.

![더티리드](https://user-images.githubusercontent.com/74235102/201449871-7729436b-8ef5-4203-b4a2-32c8e04aade1.png)

해결방법

![더티리드 해결](https://user-images.githubusercontent.com/74235102/201449874-10b030da-167a-4e08-8830-23604dde0a5b.png)

A의 작업이 아직 커밋되지 않았으니 mysql은 언두영역에 기존의 값을 저장해두고 있는다.

그래서 B가 select를 조회해도 이전 데이터인 Lara를 반환하게 되어 해결하게 된다.

> Non-Repeatable Read

한 트랜잭션 내의 같은 행에 두 번 이상 조회가 발생했는데 그 값이 다른경우를 말한다.
![반복읽기](https://user-images.githubusercontent.com/74235102/201449864-205dda3d-655b-4cdb-8df7-f1fa6ff70682.png)

B의 트랜잭션을 시작해두고 A가 update를 하고 commit을 한 후

다시 B가 select 로 조회를 하면 결과가 나오는 현상을 말함.

OracleDB의 기본 트랜잭션 격리 수준이다.

해결방법

![반복된 읽기 해결](https://user-images.githubusercontent.com/74235102/201449869-88330110-5f49-4384-a2d8-6ed903f94a03.png)

A의 트랜잭션 번호는 12, B의 트랜잭션 번호는 10이다.

12번의 트랜잭션이 중간에 update하고 commit을 진행했지만,

repeatable-read 수준에서는 각 트랜잭션마다 고유의 번호를 가지고있는데

자신의 트랜잭션 번호보다 작은 트랜잭션 번호에서 변경한것만 감지가 가능하고,

그 외에는 못보게되어 같은 쿼리를 2번 수행해도 같은 결과를 볼 수 있게된다.

> Phantom Read

![팬텀리드](https://user-images.githubusercontent.com/74235102/201449862-a006e4be-d9e0-4cbc-bd5d-718ff3b9724e.png)

해결 방안 - mysql의 innodb는 스냅샷을 이용한 일관된 읽기를 사용한다.

consistent read를 지원하기 때문인데 위에서 봤던 undo log를 이용하여 이 기능을 구현한다.

insert와 연결되지 않은 select의 경우 다른 트랜잭션의 변경 작업과 관계없이 항상 잠금을 대기하지 않고 바로 실행된다.

### 4.3.2 무결성

데이터의 정확성, 일관성, 유효성을 유지하는 것을 말하고, 무결성이 유지되어야 DB에 저장된 데이터 값과 그 값에 해당하는 현실 세계의 실제 값이 일치하는지에 대한 **신뢰** 가 생긴다.

| 이름 | 설명 |
|----------|---------------------------------------------------------|
| 개체 무결성 | 기본키로 선택된 필드는 빈 값을 허용하지 않는다. |
| 참조 무결성 | 서로 참조관계에 있는 두 테이블의 데이터는 항상 일관된 값을 유지해야 한다. |
| 고유 무결성 | 특정 속성에 대해 고유한 값을 가지도록 조건이 주어진 경우 그 속성 값은 모두 고유한 값을 가진다. |
| NULL 무결성 | 특정 속성 값에 NULL이 올 수 없다는 조건이 주어진 경우 그 속성 값은 null이 될 수 없다. |