DB Lock

DBMS 사용시에 다중으로 트랜잭션이 발생할 경우 일관성과 무결성을 유지하려면 순차적인 진행을 보장할 수 있도록 직렬화 장치가 필요한데 이런 직렬화가 가능하도록 모든 DBMS가 사용하는 체계가 Lock이다. DBMS마다 Lock을 구현하는 방식과 세부적인 기능이 많이 다르므로 각 DBMS마다 Lock을 구현하는 방식에 대해서도 알 필요가 있다.
Lock을 이해하기 쉽게 얘기하자면 화장실에서 볼일을 볼때 문을 잠근 다음, 볼일을 마치면 문을 열고 나오는 것 처럼 DB에서도 작업사항이 있을 경우 문을 잠그는 행위라고 보면된다.

Shared(공유) Lock

Shared Lock은 데이터를 읽고자(Select) 할 경우 사용된다. 다른 Lock과는 호환되지만 Exclusive(배타적) Lock과는 호환되지 않는다. (여기서 호환된다는 얘기는 한 리소스에 두 개 이상의 Lock을 동시에 설정할 수 있음을 뜻한다.)
즉, Shared Lock과 Exclusive Lock은 서로 진행중인 리소스에 접근할 수 없다

holdlock은 나중에 변경할 목적으로 레코드를 읽을 때 테이블에 다음과 같이 힌트를 준다. 단, 기본 트랜잭션 격리성 수준(Read Committed)에서만 발생한다.
아래의 경우는 PLAYER테이블의 player_id가 3번인 선수가 다른 세션에 의해 weight가 update되는 것을 막고, 80으로 update되는 것을 유지하게 함으로써 일관성을 유지시켜 준다.

set transaction isolation level read committed
begin tran

    select *
    from dbo.PLAYER with(holdlock)
    where player_id = 3

    update dbo.PLAYER
    set weight = 80
    where player_id = 3

commit

Exclusive(배타적) Lock

Exclusive Lock은 데이터를 변경(Insert, Update 등)할 때 사용되며 트랜잭션이 완료될 때까지 유지된다. Exclusive Lock은 해제될 때 까지 다른 트랜잭션은 해당 리소스에 접근할 수 없으며, 변경 및 읽기가 불가능하다.
(Exclusive Lock 끼리는 호환되지 않는다)

Update(갱신) Lock

상단의 Shared Lock예제의 쿼리가 만약에 동시에 수행되었다면, 처음에는 Shared Lock을 걸었다가 update시 Exclusive Lock을 걸게 될것이다. 그러면 두 트랜잭션은 상대편 트랜잭션에 의한 Shared Lock이 해제되기만을 바라는 DeadLock(교착상태)에 빠지게 된다. 이런상태를 방지하기 위헤 Update(갱신) Lock을 사용할 수 있으며 다음과 같이 사용할 수있다.

begin tran

    select *
    from dbo.PLAYER with(uplock)
    where player_id = 3

    update dbo.PLAYER
    set weight = 80
    where player_id = 3

commit

이렇게 하면 첫번째 트랜잭션이 Update Lock을 설정 후 Exclusive Lock전환했다가 해제 될때까지, 두번째 트랜잭션이 기다려야하므로 DeadLock(교착상태)를 방지할 수 있다

No lock(잠금해제)

트랜잭션 실행시 선행작업을 기다리는 것과 관계없이 다른 리소스에 접근이 가능하다. SELECT, INSERT, UPDATE, DELETE 등 수행문의 실행이 다 끝날때 까지 기다리지 않으며, DeadLock(교착상태)이 발생할 가능성이 있다. 또한 DB의 I/O가 굉장히 많은 경우 유연하게 처리할 수 있어서 이 방법이 유용할 수 있다.

with(nolock)을 테이블마다 걸게되면 테이블 레벨에 한정하여 설정하게 된다.
set transaction isolation level read uncommitted을 트랜잭션 상단에 설정하면 트랜잭션 세션전체의 격리수준에 영향을 미치며 테이블 전체에 with(nolock)힌트를 건 효과를 볼 수 있다.
격리수준 선언과 with(nolock)힌트를 둘다 쓰는 경우도 있는데, 둘다 써도 상관은 없다

set transaction isolation level read uncommitted
begin tran

    select *
    from dbo.PLAYER with(nolock)
    where player_id = 3

    update dbo.PLAYER
    set weight = 80
    where player_id = 3

commit

Blocking(블로킹)

Blocking은 Lock경합이 발생하여 특정 세션이 작업을 진행하지 못하고 멈춰 선 상태를 말한다.
Shared Lock 간에는 호환되기 때문에 Blocking이 발생하지 않지만 Shared Lock과 Exclusive Lock / Exclusive Lock과 Exclusive Lock 간에는 호환되지 않아 블로킹이 발생할 수 있다. 또다른 Lock경합이 발생한 이유로는 다음과 같은 이유도 있다.

1.개발자가 불필요하게 높은 잠금(lock) 레벨로 코딩하였기 때문
2.개발자가 불필요하게 긴 트랜잭션으로 코딩하였기 때문
3.사용자가 커밋해야 하는 변경사항을 커밋하지 않았기 때문

DeadLock(교착상태)

DeadLock은 두 세션이 각각 필요한 리소스를 얻기 위해 서로 상대방이 Lock을 풀기를 기다리는 상태이다. 서로의 세션간에 획득해야하는 리소스가 맞물리는 경우 잠금으로 인해 하나의 세션이 중지되지 않는 이상 빼도박도 못하는 대치상황이 된다. 비유를 하자면 좁은 골목길에 두 차량이 대치되어 있는 상황이다.