트랜잭션 잠금은 데이터베이스에서 동시성 제어를 위한 중요한 기법 중 하나입니다
Locking (잠금) 트랜잭션 잠금은 여러 트랜잭션이 동시에 같은 자원(예: 테이블, 행)을 수정하거나 읽으려고 할 때, 데이터 일관성을 유지하기 위해 사용됩니다. 일반적으로 트랜잭션이 데이터에 접근하는 동안 다른 트랜잭션이 해당 데이터에 접근하지 못하도록 잠금(Lock)을 걸어 충돌을 방지합니다.
Deadlock (교착 상태) 두 개 이상의 트랜잭션이 서로의 잠금이 해제되기를 기다리면서 발생하는 문제입니다. 예를 들어 트랜잭션 A가 리소스 X를 잠금하고, 트랜잭션 B가 리소스 Y를 잠금한 상태에서 A가 Y를 요청하고 B가 X를 요청하면, 둘 다 영원히 대기 상태에 빠지는 상황이 발생할 수 있습니다.
Lock Granularity (잠금의 세분성) 잠금은 다양한 수준에서 적용될 수 있습니다. 예를 들어 테이블 전체를 잠글 수도 있고, 특정 행만 잠글 수도 있습니다. 더 작은 단위의 잠금(예: 행 단위)은 동시성을 더 잘 지원하지만, 잠금 관리를 위한 오버헤드가 발생할 수 있습니다. 반대로 큰 단위의 잠금(예: 테이블 단위)은 동시성은 떨어지지만 관리가 더 단순합니다.
Optimistic Locking (낙관적 잠금) 낙관적 잠금은 트랜잭션이 자원을 수정할 때 잠금을 걸지 않고, 수정이 완료되기 직전에 충돌이 발생했는지 확인하는 방식입니다. 충돌이 없을 것이라는 가정 하에 동작하며, 충돌이 발생한 경우 트랜잭션을 롤백하고 다시 시도합니다.
Pessimistic Locking (비관적 잠금) 비관적 잠금은 트랜잭션이 자원을 읽거나 수정하기 전에 미리 잠금을 거는 방식입니다. 충돌 가능성이 높을 것으로 예상되는 경우 이 방식을 사용하여 트랜잭션의 충돌을 미리 방지합니다.
트랜잭션 격리 수준에서 Dirty Read 외에 자주 언급되는 다른 두 가지 문제는 Non-repeatable Read와 Phantom Read입니다. 이 세 가지는 데이터베이스 트랜잭션에서 발생할 수 있는 동시성 문제로, 트랜잭션 격리 수준을 적절히 설정하지 않으면 발생할 수 있는 문제들입니다.
예시:
트랜잭션 A가 트랜잭션 B가 커밋되지 않은 데이터를 읽습니다. 하지만 트랜잭션 B가 이후 롤백된다면, 트랜잭션 A는 유효하지 않은 데이터를 기반으로 작업한 것이 됩니다.
예시:
트랜잭션 A가 특정 데이터를 읽습니다. 이후 트랜잭션 B가 그 데이터를 수정한 후 커밋합니다. 다시 트랜잭션 A가 같은 데이터를 읽으면, 처음 읽었을 때와 다른 값이 나옵니다.
예시:
트랜잭션 A가 SELECT 쿼리로 특정 조건에 맞는 레코드를 조회합니다. 그 후 트랜잭션 B가 새로운 데이터를 삽입하고 커밋합니다. 다시 트랜잭션 A가 같은 조건으로 SELECT 쿼리를 실행하면, 처음에는 없던 새로운 레코드가 나타나게 됩니다.
요약
Dirty Read: 커밋되지 않은 데이터를 읽는 문제.
Non-repeatable Read: 동일한 데이터를 반복해서 읽을 때, 중간에 다른 트랜잭션에 의해 데이터가 변경되어 일관성이 없는 데이터를 읽는 문제.
Phantom Read: 동일한 조건으로 쿼리를 실행할 때, 중간에 다른 트랜잭션에 의해 데이터가 삽입되어 추가적인 행이 나타나는 문제.
이 문제들을 방지하기 위해 데이터베이스는 여러 트랜잭션 격리 수준을 제공합니다. 예를 들어, Serializable 수준은 가장 높은 격리 수준으로 Dirty Read, Non-repeatable Read, Phantom Read 모두를 방지하지만, 성능 저하를 초래할 수 있습니다.
좋습니다! 트랜잭션 격리 수준에 따라 Dirty Read, Non-repeatable Read, Phantom Read 문제를 방지하는 방법에 대한 답을 알려드리겠습니다.
답: Repeatable Read 이상 수준의 격리에서 Non-repeatable Read를 방지할 수 있습니다. Repeatable Read는 트랜잭션이 시작된 후 동일한 데이터를 여러 번 읽을 때, 다른 트랜잭션에서 그 데이터를 변경하지 못하도록 보장합니다. 따라서 같은 트랜잭션 내에서 읽은 값은 항상 동일하게 유지됩니다.
답: Serializable 격리 수준을 사용하면 Phantom Read를 방지할 수 있습니다. Serializable 수준은 트랜잭션들이 일련의 순서대로 직렬화되어 실행되는 것처럼 보이게 만들어, 동일한 조건의 SELECT 쿼리를 여러 번 실행할 때 중간에 다른 트랜잭션이 데이터를 추가하거나 변경할 수 없게 합니다. 이로 인해 Phantom Read 문제가 발생하지 않습니다.
답:
1. READ UNCOMMITTED:
이처럼 트랜잭션 격리 수준은 동시성 제어와 데이터 일관성 사이에서 균형을 맞추기 위해 존재하며, 높은 수준의 격리는 더 많은 동시성 문제를 방지하지만, 그만큼 성능에 부담을 줄 수 있습니다.