원자성.

여기서 말하는 원자성이란 더 이상 쪼갤 수 없다는 의미다.

원자성에 앞서 트랜잭션에 대해 간단히 정리하자.

What is transaction

  • 하나의 작업단위로 볼 수 있는 쿼리들의 집합이다.
  • 예를 들자면 송금을 들 수 있다.
    • Transaction BEGIN
    • 돈을 보내는 사람의 계좌의 잔액을 읽는다. (SELECT)
    • 돈을 보내는 사람의 계좌에서 돈을 출금한다. (UPDATE)
    • 돈을 받는 사람의 계좌에 돈을 입금한다. (UPDATE)
    • Transaction COMMIT OR ROLLBACK



트랜잭션 안에 있는 쿼리들은 모두 성공해야한다. 만약 실패하는 쿼리가 있다면 트랜잭션 내에 있는 모든 쿼리들의 결과는 롤백되어야 한다.

커밋이 되면 변경사항을 기록한다. 그런데.. 커밋이 된 게 아니라, 아직 트랜잭션이 진행 중이라면? 트랜잭션 안에 있는 단일 쿼리의 결과는 어디에 저장하지? 데이터베이스에 따라 다르다. 어떤 데이터베이스는 메모리에 올리고, 어떤 데이터베이스는 실제로 디스크에 쓰기도 한다. 트랜잭션 안에 있는 한 쿼리가 실패하거나, 아님 데이터베이스 시스템이 죽거나 등의 이유로 원자성에 의해 롤백이 되어야 하는데, 데이터베이스에 따라 롤백 작업이 굉장히 긴 시간을 소요하기도 한다.

만약 원자성이 없다면..?

Ex ) 송금 (ACCOUNT 의 ID 가 1 인 계좌에서 ID 가 2인 계좌로 100원을 송금한다.)
1. SELECT BALANCE FROM ACCOUNT WHERE ID = 1;
2. UPDATE ACCOUNT SET BALANCE - 100 WHERE ID = 1;
3. 데이터베이스 죽어버림

????? 내돈..

## 결론
Atomicity 의 의미 : 트랜잭션은 더이상 쪼갤 수 없는 하나의 작업이다!

'DB' 카테고리의 다른 글

트랜잭션 격리 수준(isolation level)  (0) 2020.07.14
[MySQL] InnoDB와 MyISAM 차이 (트랜잭션)  (0) 2020.07.07
UNION  (0) 2019.12.07
GROUP BY  (0) 2019.12.07

개요

본 포스팅의 DB환경은 MySQL 5.7.30 입니다. 테스트를 원하신다면 AUTO_COMMIT을 false로 하고 진행해주세요.

트랜잭션 격리 수준이란 ?

  • 동시에 여러 트랜잭션이 처리될 때, 특정 트랜잭션이 다른 트랜잭션에서 변경하거나 조회하는 데이터를 볼 수 있도록 허용할 지 말지를 결정한다.

트랜잭션 격리 수준의 종류

  • READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE 등으로 나뉜다.

왜 트랜잭션 격리 수준을 알아야 하는 가?

  • 동시성 문제가 있다. 데이터 부정합 문제점이 있는데, 이는 트랜잭션 격리 수준에 따라 달라진다. 아래 그림은 트랜잭션 격리 수준에 따른 데이터 부정합 표이다. 각각의 데이터 부정합의 대한 설명은 아래에서 다시 다룰 것이다.

테스트를 위한 준비

  • AUTO_COMMIT을 false로 설정한다.
  • 아래와 같이 간단한 테이블을 만들고, 데이터를 집어넣자.
create table account (
    account_id int AUTO_INCREMENT,
    login_name varchar(255) not null,
    primary key(account_id)
)charset='utf8';

insert into account(login_name)
values ('eunmo');
  • 트랜잭션 격리 수준을 설정하는 SQL과 확인하는 SQL은 다음과 같다.

    • ex ) READ UNCOMMITTED 로 설정하고 싶을 때.

      SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
      
      SHOW VARIABLES LIKE 'TX_ISOLATION';
      
    • 결과

주의!!! 테스트 할 때는 서로 다른 세션에서 수행해야한다! 현재 세션 확인하는 법 : select connection_id();

트랜잭션 격리 수준의 종류

READ UNCOMMITED

  • 각 트랜잭션에서의 변경 내용이 COMMIT이나 ROLLBACK 여부에 상관없이 다른 트랜잭션에서 보여진다. 실험을 해보자.

    1번 세션

    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
    
    UPDATE ACCOUNT
    SET LOGIN_NAME = 'GRACE LOVE'
    WHERE ACCOUNT_ID = 1;
    

    2번 세션

    begin;
    select * from account;
    

    결과

    문제

    • 결론적으로 1번 세션 트랜잭션에서 작업을 아직 완료하지 않았는데도 다른 트랜잭션이 이를 볼 수 있다.
    • 이렇게 어떤 트랜잭션에서 처리한 작업이 완료되지 않았는데도 다른 트랜잭션이 볼 수 있게 되는 현상을 Dirty read라고 한다.

    결론

    • 1번 세션에서 UPDATE 를 하고 COMMIT 하지 않았는데도 2번 세션에서는 UPDATE한 'GRACE LOVE' 가 보인다.
    • READ UNCOMMITED는 이런 데이터 부정합을 초래하므로 권장하지 않는다. 최소한 READ COMMITED 를 사용하자.

READ COMMITED

  • 어떤 트랜잭션에서 데이터를 변경했더라도 COMMIT이 완료된 데이터만 다른 트랜잭션에서 볼 수 있다.

  • 오라클에서 기본적으로 사용되는 격리수준이다.

    1번 세션

    SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
    
    UPDATE ACCOUNT
    SET LOGIN_NAME = 'GRACE LOVE'
    WHERE ACCOUNT_ID = 1;

    2번 세션

    begin;
    select * from account;
    

    결과 - COMMIT 실행 이전

    결과2 - COMMIT 실행 이후

    • 설명한 대로 COMMIT을 하지 않았기 때문에 UPDATE 한 값인 'GRACE LOVE' 가 다른 트랜잭션에선 보이지 않는다.
    • 1번 세션에서 COMMIT을 수행한 뒤 다시 2번 세션에서 조회해보자.

    문제

    • Dirty Read와 같은 부정합 문제는 발생하지 않는다.
    • 하지만 Non-Repeatable Read문제가 발생한다.
    • Non-Repeatable Read란 하나의 트랜잭션 내에서 똑같은 SELECT 쿼리를 실행했을 때 항상 같은 결과를 가져와야하는 Repeatable Read 정합성에 어긋나는 것이다.

    결론

    • SELECT 쿼리 결과는 ACCOUNT 테이블에서 가져온 것이 아니라, UNDO 영역에 백업된 컬럼 값을 가져오는 것이다.

REPEATABLE READ

  • InnoDB 스토리지 엔진의 기본 전략이다.
  • READ COMMITTED 와의 차이점은 UNDO 영역에 백업된 레코드의 여러 버전 가운데 몇 번째 이전 버전까지 찾아 들어가냐가 다르다.
  • 1번 세션이 UPDATE후 COMMIT 해도 다른 트랜잭션은 여전히 UNDO 영역을 바라보고있다.
  • PHANTOM READ가 발생할 수 있다고 하는데 InnoDB에선 발생하지 않는다 한다. 실제로 InnoDB 엔진에서 재현해보려했으나 실패했다.
    • PHANTOM READ ? 다른 트랜잭션에서 수행한 변경작업에 의해 레코드가 보였다 안보였다 하는 현상을 말한다.

SERIALIZABLE

  • 가장 엄격한 격리수준. 그만큼 동시처리성능도 가장 떨어진다. 어차피 InnoDB는 PHANTOM READ가 발생하지 않기 때문에 굳이 쓸 필요가 없다.

레퍼런스

Real MySQL - 이성욱 지음. 책 구매 링크 : http://www.yes24.com/Product/Goods/6960931

'DB' 카테고리의 다른 글

[ACID] Atomicity - 원자성  (0) 2024.02.28
[MySQL] InnoDB와 MyISAM 차이 (트랜잭션)  (0) 2020.07.07
UNION  (0) 2019.12.07
GROUP BY  (0) 2019.12.07

가장 큰 차이는 트랜잭션의 유무가 아닌가 싶다.
직접 테스트해보고 확인한 결과를 기록한다.

create table tab_myisam (
    fdpk int not null,
    primary key(fdpk)
)engine=MyISAM;


create table tab_innodb (
    fdpk int not null,
    primary key(fdpk)
)engine=InnoDB;


insert into tab_myisam (fdpk) values (3);
insert into tab_innodb (fdpk) values (3);
  • tab_myisam과 tab_innodb를 생성했다. 스토리지엔진은 이름에 따라 각각 MyISAM과 InnoDB로 설정해줬다.
  • 값을 넣어준다. 두 테이블 모두 fdpk 라는 컬럼에 3 이라는 값을 넣어줬다. 이제 실험!

insert into tab_myisam (fdpk) values(1), (2), (3);
insert into tab_innodb (fdpk) values(1), (2), (3);
  • fdpk에 1, 2, 3을 넣는다.
  • 우리가 예상하기로는 1, 2를 넣고 3을 넣는 순간 unique 제약 조건에 걸려서 모두 롤백되어야 한다.
  • myisam엔진을 쓰는 테이블인 tab_myisam을 select 해보면, (select * from tab_myisam)
    1,2,3 모두 값이 들어가있다. 트랜잭션을 지원하지 않기 때문!
  • 그에 반해 innodb 엔진을 쓰는 테이블인 tab_innodb를 select해보면, (select * from tab_innodb)
    처음에 값을 넣어준 3 외에는 없는 걸로 나온다. 트랜잭션을 지원하기 때문이다!

```

'DB' 카테고리의 다른 글

[ACID] Atomicity - 원자성  (0) 2024.02.28
트랜잭션 격리 수준(isolation level)  (0) 2020.07.14
UNION  (0) 2019.12.07
GROUP BY  (0) 2019.12.07
  • UNION
    • 테이블 간 합집합을 구할 때.
    • SELECT * FROM sample1;
      • a : 1, 2, 3
    • SELECT * FROM sample2;
      • a : 2, 10, 11
    • SELECT * FROM sample1 UNION SELECT * FROM sample2;
      • a : 1, 2, 3, 10, 11
    • 두 개의 집합에서 겹치는 부분은 공통요소가 되므로 중복 제거된다.
      • 중복을 제거하기 싫다면 UNION ALL을 쓸 것.
    • ORDER BY는 가장 마지막의 SELECT 명령에 붙여야한다.

'DB' 카테고리의 다른 글

[ACID] Atomicity - 원자성  (0) 2024.02.28
트랜잭션 격리 수준(isolation level)  (0) 2020.07.14
[MySQL] InnoDB와 MyISAM 차이 (트랜잭션)  (0) 2020.07.07
GROUP BY  (0) 2019.12.07

+ Recent posts