Skip to content

[5장] 트랜잭션과 잠금 #8

@janeljs

Description

@janeljs

05 트랜잭션과 잠금

5.1 트랜잭션

  • 논리적인 작업 셋이 100% 적용되거나 아무것도 적용되지 않아야 함을 보장
    • COMMIT
    • ROLLBACK
  • 트랜잭션이 없다면, 여러 동작을 수행했을 때, 중간 작업이 실패 했을 경우 손수 롤백 해야하는 불편함이 있다.

5.1.1 MySQL에서의 트랜잭션

5.1.2 주의사항

  • 트랜잭션의 범위는 최소화해야 한다.
  • 모놀리식 서비스는 트랜잭션을 하나로 관리가 가능하지만, MSA 는 하나의 트랜잭션으로 묶기 어렵다.
  • SAGA 패턴: MSA 에서의 트랜잭션을 SAGA 라는 단위로 묶는다?

5.2 MySQL 엔진의 잠금

  • 읽기 잠금
  • 쓰기 잠금

5.2.1 글로벌 락

  • 서버 전체
  • 백업 락
    • MySQL 8.0에서는 데이터 변경을 허용하는 백업 락 추가됨
    • 테이블 정보 수정 허용 x

5.2.2 테이블 락

  • 명시적 락
  • 묵시적 락

5.2.3 네임드 락

5.2.4 메타데이터 락

  • 데이터베이스 객체의 이름이나 구조 변경 시 획득하는 잠금

5.3 InnoDB 스토리지 엔진 잠금

  • 레코드 기반 잠금
  • 최근 버전에서는 트랜잭션 상태와 잠금에 대해서 조회할 수 있는 여러 모니터링 방법 추가

5.3.1 InnoDB 스토리지 엔진의 잠금

5.3.1.1 레코드 락

  • 레코드 자체만을 잠금
  • MySQL은 인덱스의 레코드를 잠금
  • 보조 인덱스의 경우 넥스트 키 락 / 갭 락
  • PK 또는 유니크 인덱스의 경우 레코드 락

5.3.1.2 갭 락

  • 레코드와 바로 인접한 레코드 사이의 간격만을 잠금

5.3.1.3 넥스트 키 락

  • STATEMENT 포맷의 바이너리 로그를 사용하는 경우 REPEATABLE READ 격리 수준 사용해야 함
  • 바이너리 로그에 기록되는 쿼리가 레플리카 서버에서 실행될 때 소스 서버에서 만들어 낸 결과와 동일한 결과를 만들어내도록 보장하는 것이 주 목적
  • 가능하면 바이너리 로그 포맷을 ROW 형태로 바꾸기
    • MySQL 8.0 에서는 기본 설정
  • PK Clustered Index 는 Sparse Index 로 구성 가능하고
  • Secondary Index 는 dense index 로 구성가능하다.
  • 레플리카 서버와 소스 서버에서 만든 쿼리결과가 동일하도록 보장
  • 팬텀 리드 문제를 해결하기 위해서 넥스트 키 락이 필요
  • 레코드 락과 갭락을 둘다 활용해서 구현된 개념이 넥스트 키 락

5.3.1.4 자동 증가 락

  • AUTO_INCREMENT 에 대한 락
  • INSERT, REPLACE

5.3.2 인덱스와 잠금

  • 인덱스를 사용하면서 접근한 레코드 모두를 잠금
  • 그러므로 인덱스 설계가 중요

5.3.3 레코드 수준의 잠금 확인 및 해제

  • 잠금 / 트랜잭션 정보에 대한 조회

5.4 MySQL의 격리 수준

  • DIRTY READ
  • NON-REPEATABLE READ
  • PHANTOM READ

5.4.1 READ UNCOMMITTED

  • DIRTY READ
  • NON-REPEATABLE READ
  • PHANTOM READ

5.4.2 READ COMMITTED

  • NON-REPEATABLE READ
  • PHANTOM READ

5.4.3 REPEATABLE READ

  • PHANTOM READ

범위 조회 다른 트랜잭션
id 110 -> 1, 4, 4, 9 insert 7 OK
id 1
10 -> 1, 4, 4, 7, 9 PHAMTOM READ

  • PHANTOM READ
  • JPA는 캐시 구조가 있어 REPEATABLE READ를 기본적으로 지원

5.4.4 SERIALIZABLE

쿼리 테스트용

CREATE TABLE test(
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  codesquad BIGINT NOT NULL,
);

INSERT INTO test (codesquad) VALUES (1), (3), (5), (7), (10);

START TRANSACTION;
SELECT * FROM test WHERE id >= 7;
COMMIT;

START TRANSACTION;
EXPLAIN SELECT * FROM test WHERE id = 1 FOR UPDATE;
COMMIT;

기타


텍스트

1, 2, 3, 4, 5, ... 10000

인덱스 -> 찾을수 있는거에 대해서, 데이터 페이지 주소를 매핑
id 데이터 페이지 번호 (페이지 주소)
1 -> 1
2 -> 1
3 -> 1
4
5
6
..

1000 -> 1
1001 -> 2
...
1400 -> 2
...
2000 -> 2

10000
-> dense index

index (first_name, last_name)
first_name, record id

GERGI 10001
GERGI 10002
GERGI 10003
GERGI 10007
GERGI 10004
GERGI 10006

GERGY

SELECT 언제든 가능
SELECT FOR SHARE
SELECT FOR UPDATE

UPDATE WHERE first_name = GERGI AND last_name=Klassen

1 -> 1
1001 -> 2
2001 -> 3
-> sparse index
pk clustered index <-

secondary index -> dense index

페이지 1
1,
2
3
4
..
1000

페이지 2
1001
1002

...

2000

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions