본문 바로가기
프로그래밍/데이터베이스

[데이터베이스] 트랜잭션과 격리성

by 사바라다 2020. 10. 4.

안녕하세요. 평소에 포스팅하던 내용과는 조금 떨어진 이론적인 내용을 포스팅하고자 합니다. DB는 트랜잭션 단위로 처리된다고 합니다. 유명한 All Or Nothing이 DB의 트랜잭션에서 나온 이야기입니다. 오늘은 여러분들께 DB를 이용할 때의 트랜잭션과 그리고 한발 더 나아가 격리성(Isolation)에 대해서 알아보는 시간을 가지도록 하겠습니다.

트랜잭션(Transaction)

만들고 있는 프로젝트의 로직중에 DB table에 정보를 insert하는 로직이 있습니다. table은 정규화 되어있으며 A, B, C 테이블에 차례대로 테이터를 insert한다고 하겠습니다. 테이블이 쪼개져 있으므로 테이블간의 데이터 정합성을 유지하는게 중요합니다. 만약 A, B에는 insert하고 C에 insert 하기전 서버가 에러 또는 특정 작업에 의해 정상적으로 처리하지 못하는 상황이 되었다고 하겠습니다. 그렇다면 결과적으로 이 데이터는 믿을 수 없는 데이터가 됩니다. 이를 해결하기 위한 방법으로 DB는 All Or Nothing전략을 취합니다. 즉, A, B, C에 정상적으로 insert하거나 아무곳도 insert하지 않는 것입니다. DB에서는 이 전략을 취하기 위해 트랜잭션이라는 단위를 사용합니다. 트랜잭션 단위는 나누어지지 않는 최소한의 단위라고 정의합니다. 위 로직에 트랜잭션이 적용되면 오류가 났다면 A, B에 insert한 것을 Rollback함으로써 Nothing으로 전략을 취합니다.

트랜잭션은 4가지의 특징을 가집니다. 이를 앞글자만따서 ACID라고 부릅니다.

  • 원자성(Atomicity)
    • 트랜잭션은 더 이상 분해가 불가능한 업무의 최소단위이므로, 전부 처리되거나 아예 하나도 처리되지 않아야 한다.
  • 일관성(Consistency)
    • 일관된 상태의 데이터베이스에서 하나의 트랜잭션을 성공적으로 완료하고 나면 그 데이터베이스는 여전히 일관된 상태여야 한다. 즉, 트랜잭션 실행의 결과로 데이터베이스 상태가 모순되지 않아야 한다.
  • 격리성(Isolation)
    • 실행 중인 트랜잭션의 중간결과를 다른 트랜잭션이 접근할 수 없다.
  • 영속성(Durability)
    • 트랜잭션이 일단 그 실행을 성공적으로 완료하면 그 결과는 데이터베이스에 영속적으로 저장된다.

트랜잭션 격리성(Transaction Isolation)

트랜잭션의 격리성에 대해서 조금 더 깊게 보도록 하겠습니다. 격리성은 위의 특징에서 살펴보았듯이 실행 중인 트랜잭션의 중간결과를 다른 트랜잭션이 접근할 수 없다.라는 정의를 가지고 있습니다. 막연하게 접근할 수 없다라기 보다는 일반적으로 접근 레벨이 있으며 DB에 따라 설정이 가능합니다. 이런 격리성은 강하게 처리할 수 있으며 반대로 약하게 처리할 수도 있습니다. 아래에서 조금 더 살펴보겠습니다.

격리성으로 인해 나타날 수 있는 문제점

격리성으로 인해 나타날 수 있는 문제점은 일반적으로 Dirty Read, Non-Repeatable Read, Phantom Read 3가지라고 합니다.

Dirty Read

Dirty Read는 다른 트랜잭션에 의해 수정됐지만 아직 커밋되지 않은 데이터를 읽는 것을 말합니다. 아래의 이미지를 보시면 이해되실 거라 생각됩니다. 이런 경우 Transaction_1이 정상처리되지 않고 Rollback될 수 있습니다. 이럴 경우 그 값을 이미 읽은 Transaction_2는 잘못된 값을 가지고 본인의 로직을 처리하는 상태에 놓이게 됩니다.

Non-Repeatable Read

Non-Repeatable Read는 한 트랜잭션 내에서 같은 Key를 가진 Row를 두 번 읽었는데 그 사이에 값이 변경되거나 삭제되어 결과가 다르게 나타나는 현상을 말합니다.

Phantom Read

한 트랜잭션 내에서 같은 쿼리를 두 번 수행했는데, 첫 번째 쿼리에서 없던 유령(Phantom) 레코드가 두 번째 쿼리에서 나타나는 현상을 말합니다.

여기서 Phantom Read와 Non-Repeatuable Read를 햇갈릴 수 있습니다. Non-Repeatable Read는 1개의 Row의 데이터의 값이 변경되는 것이며 Phanton Read는 다건을 요청하는 것에 대해서 데이터의 값이 변경되는 것입니다.

지정할 수 있는 격리성 수준

그렇다면 이제 DataBase에서 제공하는 격리성 수준(Transaction Isolation Level)에 대해서 알아보도록 하겠습니다. 아래의 4개의 격리수준은 ANSI/ISO SQL 표준(SQL92)에서 정의한 내용입니다.

Read Uncommitted

트랜잭션에서 처리 중인 아직 커밋되지 않은 데이터를 다른 트랜잭션이 읽는 것을 허용합니다. 해당 수준에서는 Dirty Read, Non-Repeatable Read, Phantom Read가 일어날 수 있습니다. 이 설정은 정합성에 문제가 있기 때문에 권장하는 설정은 아닙니다.

Read Committed

트랜잭션이 커밋되어 확정된 데이터만 다른 트랜잭션이 읽도록 허용합니다. 따라서 Dirty Read의 발생가능성을 막습니다. 커밋 되지 않은 데이터에 대해서는 실제 DB 데이터가 아닌 Undo 로그에 있는 이전 데이터를 가져오는 것입니다. 하지만 Non-Repeatable ReadPhanton Read에 대해서는 발생 가능성이 있습니다.

Repeatable Read

트랜잭션내에서 삭제, 변경에 대해서 Undo 로그에 넣어두고 앞서 발생한 트랜잭션에 대해서는 실제 데이터가 아닌 Undo 로그에 있는 백업데이터를 읽게 합니다. 이렇게 함으로써 트랜잭션 중 값의 변경에 대해서 일정한 값으로 처리할 수 있습니다. 이렇게하면 삭제와 수정에 대해서 트랜잭션내에서 불일치를 가져오던 Non-Reapeatable Read를 해소할 수 있습니다. Multiversion Concurrency Control

Serializable Read

트랜잭션 내에서 쿼리를 두 번 이상 수행할 때, 첫 번째 쿼리에 있던 레코드가 사라지거나 값이 바뀌지 않음은 물론 새로운 레코드가 나타나지도 않도록 하는 설정입니다.

마무리

오늘은 이렇게 트랜잭션과 그 격리성에 대해서 알아보는 시간을 가졌습니다.

오랜만에 이론에 대해서 이야기를 나눠봤는데 어떠셨는지요. 다음번에는 또 다른 이야기로 찾아뵙겠습니다.

감사합니다.

참조

stack_overflow_what-is-the-difference-between-non-repeatable-read-and-phantom-read

DBGuide_net+transaction

nesoy_blog_트랜잭션의 격리 수준(isolation Level)이란?

 

 

댓글