READ COMMITTED CLASS with READ UNCOMMITTED INSTANCES

이 격리 수준은 트랜잭션이 다른 트랜잭션에서 수정 중인 클래스를 읽지 못하게 하며, 이후에 갱신되거나 롤백될 수도 있는 더티 인스턴스를 읽도록 허용한다. 트랜잭션은 클래스와 인스턴스에 대한 읽기가 반복 불가능(non-repeatable read)할 수도 있다. 이것은 트랜잭션이 동일한 클래스를 두 번 읽게 되면 다른 두 커밋된 값을 읽을 수 있고, 동일한 인스턴스를 두 번 읽게 되면 커밋되었거나 그렇지 않은 서로 다른 두 값을 읽을 수 있음을 의미한다. 커밋되지 않은 인스턴스는 그 인스턴스를 갱신하는 트랜잭션에 의해 롤백될 수 있는데, 그 이유는 다른 트랜잭션이 두 번 읽는 간격 동안에 객체를 갱신하기 때문이다. 마찬가지로, 한 질의가 두 번 수행되면 두 수행 결과가 다를 수 있다. 이것은 두 질의가 수행되는 간격 동안에 커밋되거나 그렇지 않은 인스턴스에 대한 삽입, 갱신, 삭제가 있을 수 있기 때문이다. 질의되는 클래스는 더 이상 존재하지 않을 수도 있고 속성 일부는 추가되었거나 삭제되었을 수도 있다. REPEATABLE READ 격리 수준에서는 클래스에 대한 갱신은 불가능한데, 그 이유는 트랜잭션이 끝까지 클래스에 대한 잠금을 가지고 있기 때문이다.

아래는 이 격리 수준의 규칙이다.

이 격리 수준은 배타 잠금에 대해서 2단계 잠금을 한다. 하지만 공유 잠금은 인스턴스에 대해 획득할 수 없고 클래스에 대한 공유 잠금 또는 의도 공유 잠금은 클래스가 읽혀진 후 곧바로 해제된다.

예제

한 트랜잭션은 인스턴스를 삽입하고 클래스를 갱신하며 다른 클래스는 다양한 관점에서 클래스에 질의를 한다. 트랜잭션 T1은 임의의 격리 수준을 가지며 트랜잭션 T2는 READ COMMITTED CLASS with READ UNCOMMITTED INSTANCES 격리 수준을 가진다.  이 예제에서는 partition2 클래스가 이전에 존재하지 않을 것으로 가정하고 생성한다.

  1. 트랜잭션 T1은 partition2 클래스를 생성하고 인스턴스를 삽입한다. 트랜잭션 T1이 커밋되자마자 CUBRID는 트랜잭션 T1이 가지고 있던 잠금을 해제한다. 트랜잭션 T2는 partition2 클래스에 질의한다.
      1. User1 (T1):
    1. SET TRANSACTION ISOLATION LEVEL READ COMMITTED CLASS, READ UNCOMMITTED INSTANCES;
      ;xrun
      ;autocommit off
      create class participant2 (host_year integer, nation_code char(3));
      insert into participant2 (host_year, nation_code) values (2008, ‘AUS’);
      commit work;
      ;xrun
      1 rows inserted.
      1. User2 (T2):
    2. SET TRANSACTION ISOLATION LEVEL READ COMMITTED CLASS, READ UNCOMMITTED INSTANCES;
      ;xrun
      ;autocommit off
      select host_year, nation_code from participant2;
      ;xrun
      === <Result of SELECT Command in Line 2> ===
          host_year  nation_code
      ===================================
               2008  'AUS'
      1 rows selected.
  2. 트랜잭션 T1은 participant2 클래스에 또 하나의 인스턴스를 삽입한다. 트랜잭션 T2가 participant2 클래스에 질의했을 때는 커밋된 첫 번째 인스턴스만 보이게 되는데, 그 이유는 이 예제에서 두 번째 인스턴스가 데이터베이스로 출력되지 않았기 때문이다.
      1. User1 (T1):
    1. insert into participant2 (host_year, nation_code) values (2004, ‘FRA’);
      ;xrun
      1 rows inserted.
      1. User2 (T2):
    2. select * from participant2;
      ;xrun
      === <Result of SELECT Command in Line 1> ===
          host_year  nation_code
      ===================================
               2008  'AUS'
      1 rows selected.
      1 command(s) successfully processed.
  3. 트랜잭션 T1은 participant2 클래스를 갱신하고 gold 속성을 추가한다. 이 때 트랜잭션 T2가 이 클래스에 질의를 하면 대기 상태가 되는데, 이는 ALTER 문 때문이다. 이는 다른 격리 수준에서도 가능한데, 그 이유는 트랜잭션의 끝까지 클래스에 대한 잠금을 유지하기 때문이다.
      1. User1 (T1):
    1. alter class participant2
      add attribute gold integer;
      ;xrun
      1 command(s) successfully processed.
      1. User2 (T2):
    2. select * from participant2;
      ;xrun
  4. 트랜잭션 T1은 participant2 클래스에 gold 속성을 포함한 또 하나의 인스턴스를 삽입한다. 트랜잭션 T1이 연산을 커밋하고 트랜잭션 T2가 다시 진행된다. 트랜잭션 T2는 완전히 다른 스키마(클래스)를 보게 됨을 주의해야 한다.
      1. User1 (T1):
    1. insert into participant2 (host_year, nation_code, gold)
      values (2012, ‘KOR’, 20);
      commit work;
      ;xrun
      1 command(s) successfully processed.
      1. User2 (T2):
    2. === <Result of SELECT Command in Line 1> ===
          host_year  nation_code                  gold
      ======================================
               2008  'AUS'                        NULL
               2004  'FRA'                        NULL
               2012  'KOR'                          20

      3 rows selected.