안녕하세요! 오늘은 SQL Isolation(격리 수준)에 대해서 공부해 볼건데요. 물리적 데이터베이스에서 여러 사용자가 동시에 작업을 수행할 때, 데이터의 일관성과 격리를 보장하는 것은 매우 중요합니다. 지금부터 가볍게 알아보는 시간을 가지겠습니다. 🤨
트랜잭션 격리수준 (Transaction Isolation) 🖥
트랜잭션(Transaction) : 데이터베이스에서의 논리적인 작업을 나타내며 데이터의 읽기, 쓰기, 수정, 삭제등의 작업을 의미합니다. 트랜잭션은 데이터베이스의 일관성을 보장하기 위해 사용되며 이러한 작업들은 한개의 단위로 묶여 있고 결과적으로 모두 성공하거나 모두 실패해야 합니다.
격리 수준(Isolation) : 어떤 트랜잭션의 변경 사항이 다른 트랜잭션에 어떤 영향을 나타내는지 정의하는 데이터베이스 속성입니다. 격리 수준은 트랜잭션 간의 상호 작용을 제어하며 격리 수준 설정을 통해 트랜잭션 간의 데이터 무결성을 안정적으로 유지할 수 있습니다.
격리 수준의 종류
-
READ UNCOMMITTED : 다른 사람이 아직 저장하지 않은 정보를 읽을 수 있습니다. 다만, 이것은 정보의 일관성을 보장하지 않습니다. 예를 들어, 다른 사람이 아직 계좌 이체를 완료하지 않은 정보를 읽을 수 있습니다.
-
READ COMMITTED : 다른 사람이 저장한 정보만 읽을 수 있습니다. 아직 저장하지 않은 정보는 읽을 수 없습니다.
-
REPEATABLE READ : 같은 정보를 반복해서 읽어도 결과가 일관적으로 유지됩니다. 다른 사람이 정보를 변경하더라도 현재 작업 중인 트랜잭션에서 조회한 정보는 일관성을 유지합니다.
-
SERIALIZABLE : 가장 엄격한 격리 수준으로, 다른 트랜잭션이 완료될 때까지 결과를 알 수 없습니다.
예시 : 온라인 게임
- READ UNCOMMITTED : 다른 플레이어가 아직 게임 점수를 저장하지 않은 상황에서, 나는 그 정보를 읽을 수 있지만, 정보의 일관성을 보장하지 않습니다.
- READ COMMITTED : 다른 플레이어가 게임 점수를 저장한 후에 나는 그 정보를 읽을 수 있습니다. 아직 저장하지 않은 정보는 읽을 수 없습니다.
- REPEATABLE READ : 같은 게임을 반복해서 플레이해도 결과가 일관적으로 유지됩니다. 다른 플레이어가 정보를 변경하더라도 현재 게임 중인 플레이어는 조회한 정보를 일관적으로 유지합니다.
- SERIALIZABLE : 여러 플레이어가 동시에 같은 게임에 참여하려고 할 때, 하나의 플레이어는 다른 플레이어가 게임을 완료할 때까지 기다려야 합니다.
트랜잭션 이상(Transaction Anomaly) 👽
트랜잭션 격리 수준(Isolation)은 트랜잭션 이상 현상에서 사용하게 되는데 트랜잭션 이상 현상에는 대표적으로 3가지가 있습니다.
Dirty Read (더티 리드)
Dirty Read는 트랜잭션에서 다른 트랜잭션에서 아직 커밋되지 않은 데이터를 읽는 현상을 가리키며 다른 트랜잭션에서 변경 중인 데이터를 읽을 때,
그 데이터가 롤백되어 원래 값으로 돌아가면 문제가 발생합니다. 이는 데이터의 무결성을 위반하며, 일관성을 해치게 됩니다.
Non-Repeatable Read (논-리피터블 리드)
Non-Repeatable Read는 동일한 트랜잭션 내에서 동일한 데이터를 두 번 읽을 때 데이터가 변경되는 현상을 가리키며 트랜잭션이 한 번의 쿼리에서 동일한 데이터를 두 번 이상 읽을 때, 첫 번째 읽기와 두 번째 읽기 사이에 다른 트랜잭션에서 데이터를 수정하면 문제가 발생합니다. 이로 인해 트랜잭션 내에서 데이터 일관성이 깨지게 됩니다.
Phantom Read (팬텀 리드)
Phantom Read는 동일한 쿼리를 두 번 이상 실행할 때, 다른 트랜잭션에서 데이터를 추가 또는 삭제하는 현상을 가리키며 트랜잭션이 동일한 쿼리를 두 번 실행하면, 첫 번째 실행에서 없던 데이터가 두 번째 실행에서 나타날 수 있습니다. 이로 인해 쿼리 결과가 일관성을 가지지 않게 되며, 데이터베이스의 무결성이 위반됩니다.
더욱 이해하기 쉽도록 예시를 들어보겠습니다.
- Dirty Read (더티 리드):
이것은 누군가의 비밀 일기를 읽어버리는 것과 같습니다. A가 일기를 쓰고 있고 아직 일기를 다 작성하지 않았는데 B가 A의 일기를 읽어버린다면 A의 비밀 일기 내용이 노출됩니다. Dirty Read는 다른 사람의 아직 완료되지 않은 정보를 읽는 것을 의미합니다. 이것은 데이터베이스에서 다른 트랜잭션이 아직 완료하지 않은 정보를 읽을 수 있는 상황을 나타냅니다.
- Non-Repeatable Read (논-리피터블 리드):
이것은 책을 읽는 도중에 내용이 바뀌는 것과 같습니다. A가 책을 읽고 있는데 B가 책의 내용을 수정한다면 A는 같은 책을 다시 읽을 때 다른 내용을 볼 것입니다. Non-Repeatable Read는 동일한 정보를 두 번 읽을 때 결과가 달라지는 상황을 의미합니다. 데이터베이스에서 다른 트랜잭션이 정보를 변경하면, 같은 정보를 다시 읽을 때 결과가 바뀔 수 있습니다.
- Phantom Read (팬텀 리드):
이것은 마치 미래의 사건을 예측하는 것과 같습니다. 당신이 내일 어떤 음식을 먹을지 예측하려고 하는데, 예측한 대로 음식이 준비되지 않는다면, 당신은 놀랄 것입니다. Phantom Read는 동일한 쿼리를 두 번 실행할 때 결과가 달라지는 상황을 나타냅니다. 다른 트랜잭션이 데이터를 추가하거나 삭제할 때, 같은 쿼리를 다시 실행하면 결과가 바뀔 수 있습니다.
트랜잭션 격리수준 설정 방법 ⚙
위와 같은 트랜잭션 이상을 해결하기 위해서는 데이터베이스에서 격리 수준을 설정해야하며, 설정한 뒤에는 데이터베이스 관리 시스템이 이러한 문제를 제어하도록 도와주게 됩니다.
MySQL에서는 격리 수준을 설정하려면 SET TRANSACTION 명령을 사용할 수 있습니다.
--READ UNCOMMITTED
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
--SERIALIZABLE
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
참고로 MySQL/MariaDB에서는 READ COMMITTED, REPEATABLE READ 격리 수준이 기본 설정이며, 별도의 설정이 필요하지 않습니다.
트랜잭션이 다른 트랜잭션으로부터 어떠한 영향을 미치는지에 대해 분석하고 그 상황에 맞추어 격리 수준을 설정한다면 데이터의 일관성, 무관성을 지킬 수 있다는 것을 알게 되었습니다. 지금까지 트랜잭션 격리 수준에 대해서 가볍게 알아보았습니다. 감사합니다! 😊