테이블 잠금과의 트랜잭션 격리 수준 관계


105

나는 4 가지 수준의 격리를 읽었습니다.

Isolation Level       Dirty Read    Nonrepeatable Read  Phantom Read  
READ UNCOMMITTED      Permitted       Permitted           Permitted
READ COMMITTED              --        Permitted           Permitted
REPEATABLE READ             --             --             Permitted
SERIALIZABLE                --             --              --

각 트랜잭션 격리가 테이블에서 취하는 잠금 을 이해 하고 싶습니다.

READ UNCOMMITTED - no lock on table
READ COMMITTED - lock on committed data
REPEATABLE READ - lock on block of sql(which is selected by using select query)
SERIALIZABLE - lock on full table(on which Select query is fired)

다음은 트랜잭션 격리에서 발생할 수있는 세 가지 현상입니다.
Dirty
Read- 잠금 없음 Nonrepeatable Read- 커밋 된 데이터에 대한 잠금으로 더티 읽기 없음
Phantom Read -SQL 블록에 대한 잠금 (선택 쿼리를 사용하여 선택)

이러한 격리 수준을 정의 하는 위치 를 이해하고 싶습니다 . jdbc / hibernate 수준에서만 또는 DB에서도

추신 : 오라클의 격리 수준 의 링크를 살펴 보았지만 서투른 것처럼 보이며 데이터베이스별로 이야기합니다.


3
이것은 전적으로 데이터베이스에 달려 있습니다. 다른 데이터베이스는 격리 수준에 대해 다른 알고리즘을 사용할 수 있습니다. 일부는 MVCC (선택 쿼리에 대한 잠금 없음)를 사용하고 일부는 엄격한 2 단계 잠금 (공유 및 배타적 잠금)을 사용합니다.
brb tea 2015

답변:


157

각 트랜잭션 격리가 테이블에서 취하는 잠금 을 이해 하고 싶습니다.

예를 들어 3 개의 동시 프로세스 A, B 및 C가 있습니다. A는 트랜잭션을 시작하고 데이터를 쓰고 커밋 / 롤백합니다 (결과에 따라 다름). B SELECT는 데이터를 읽는 명령문을 실행합니다 . C는 데이터를 읽고 업데이트합니다. 이 모든 프로세스는 동일한 테이블 T에서 작동합니다.

  • READ UNCOMMITTED- 테이블에 대한 잠금이 없습니다. 테이블에 쓰는 동안 테이블의 데이터를 읽을 수 있습니다. 이것은 A가 데이터를 쓰고 (커밋되지 않음) B가이 커밋되지 않은 데이터를 읽고 사용할 수 있음을 의미합니다 (어떤 목적 으로든). A가 롤백을 실행하면 B는 여전히 데이터를 읽고 사용했습니다. 이것은 물리적으로 관련되지 않은 테이블에 데이터 허점을 초래할 수 있기 때문에 데이터 작업에 가장 빠르지 만 가장 안전하지 않은 방법입니다 (예, 실제 앱에서는 두 테이블이 논리적으로 연결될 수 있지만 물리적으로 관련되지는 않음 = \).
  • READ COMMITTED- 커밋 된 데이터에 대한 잠금. 커밋 된 데이터 만 읽을 수 있습니다. 이것은 A가 데이터를 쓰고 B는 A가 커밋을 실행할 때까지 A가 저장 한 데이터를 읽을 수 없음을 의미합니다. 여기서 문제는 C가 B 클라이언트에서 읽고 사용 된 데이터를 업데이트 할 수 있다는 것입니다.
  • REPEATABLE READ -SQL 블록에 대한 잠금 (선택 쿼리를 사용하여 선택됨). 이것은 B가 어떤 조건 하에서 데이터를 읽는다는 것을 의미합니다. 즉 WHERE aField > 10 AND aField < 20, A가 aField값이 10에서 20 사이 인 데이터를 삽입 한 다음 B가 데이터를 다시 읽고 다른 결과를 얻습니다.
  • SERIALIZABLE- 전체 테이블에 대한 잠금 (Select 쿼리가 실행되는). 즉, B는 데이터를 읽고 다른 트랜잭션은 테이블 의 데이터수정할 수 없습니다 . 이것은 데이터 작업에 가장 안전하지만 가장 느린 방법입니다. 또한 간단한 읽기 작업 이 테이블을 잠그기 때문에 프로덕션에 심각한 문제가 발생할 수 있습니다. T 테이블이 송장 테이블이고 사용자 X는 그날의 송장을 알고 싶어하고 사용자 Y는 새 송장을 만들고 싶어한다고 가정합니다. X가 인보이스를 읽는 동안 Y는 새 인보이스를 추가 할 수 없습니다 (그리고 돈에 관한 것이라면 사람들, 특히 사장님은 정말 화가납니다).

이러한 격리 수준을 정의 하는 위치 를 이해하고 싶습니다 . JDBC / 최대 절전 수준에서만 또는 DB에서도

JDBC를 사용하여 다음을 사용하여 정의합니다. Connection#setTransactionIsolation .

Hibernate 사용 :

<property name="hibernate.connection.isolation">2</property>

어디

  • 1 : 커밋되지 않은 읽기
  • 2 : 커밋 된 읽기
  • 4 : 반복 가능한 읽기
  • 8 : 직렬화 가능

Hibernate 구성은 여기 에서 가져옵니다 . (죄송합니다. 스페인어로되어 있습니다).

그런데 RDBMS에서도 격리 수준을 설정할 수 있습니다.

그리고 계속해서 ...


docs.oracle.com/cd/B12037_01/server.101/b10743/consist.htm Oracle에 추가하기 : 트랜잭션 시작시 다음 명령문 중 하나를 사용하여 트랜잭션의 격리 수준을 설정할 수 있습니다. SET TRANSACTION ISOLATION LEVEL READ COMMITTED; 일련 화 가능한 트랜잭션 격리 수준 설정 트랜잭션 읽기 전용으로 설정하십시오.
학습자

2
또한 SET TRANSACTION 문으로 각 트랜잭션을 시작하는 네트워킹 및 처리 비용을 절약하기 위해 ALTER SESSION 문을 사용하여 모든 후속 트랜잭션에 대한 트랜잭션 격리 수준을 설정할 수 있습니다. ALTER SESSION SET ISOLATION_LEVEL SERIALIZABLE; ALTER SESSION SET ISOLATION_LEVEL READ COMMITTED;
학습자

12
REPEATABLE READ와 관련하여-나는 그것을 보여주는 더 좋은 예가 다음과 같다고 생각합니다. B는 트랜잭션을 시작하고, SQL 블록에서 데이터를 읽습니다. WHERE aField> 10 AND aField <20, 해당 데이터는 트랜잭션이 끝날 때까지 잠 깁니다. A는 해당 데이터를 업데이트하려고하지만 잠금 때문에 대기합니다. 이제 B가 동일한 트랜잭션에서 해당 데이터를 다시 읽을 때 잠겨 있기 때문에 동일한 데이터를 읽는 것이 보장됩니다. 틀 렸으면 말해줘.
BornToCode

1
@LuiggiMendoza 일반적인 개념으로 격리 수준은 Dirty Read , Non-Repeatable ReadPhantom Rows에 관한 것 입니다. 잠금 (S2PL) 또는 MVCC는 여러 공급 업체를위한 구현입니다.
brb tea 15.09.27

4
@LuiggiMendoza-정확하지 않았습니다. B가 읽은 데이터는 변경되지 않았지만 B가 선택한 결과는 더 많은 행을 반환 할 수 있습니다. A가 이미 읽은 행을 A가 해제 할 때까지 수정할 수 없기 때문 입니다. 그러나 A는 where 조건을 한정하는 새 행을 삽입 할 수 있습니다 (따라서 다음에 A가 선택을 실행할 때 더 많은 행이있는 다른 결과 (팬텀 읽기)를 얻습니다).
BornToCode

9

brb tea가 말했듯이 데이터베이스 구현 및 사용하는 알고리즘 (MVCC 또는 2 단계 잠금)에 따라 다릅니다.

CUBRID (오픈 소스 RDBMS) 이 두 가지 알고리즘의 개념을 설명 합니다.

  • 2 단계 잠금 (2PL)

첫 번째는 T2 트랜잭션이 A 레코드를 변경하려고 할 때 T1 트랜잭션이 이미 A 레코드를 변경했음을 알고 T2 트랜잭션이 T1 트랜잭션이 커밋 또는 롤링되는지 여부를 알 수 없기 때문에 T1 트랜잭션이 완료 될 때까지 기다립니다. 뒤. 이 방법을 2PL (Two-phase locking)이라고합니다.

  • 다중 버전 동시성 제어 (MVCC)

다른 하나는 각각의 T1 및 T2 트랜잭션이 자신의 변경된 버전을 갖도록 허용하는 것입니다. T1 트랜잭션이 A 레코드를 1에서 2로 변경 한 경우에도 T1 트랜잭션은 원래 값 1을 그대로두고 A 레코드의 T1 트랜잭션 버전이 2라고 씁니다. 그러면 다음 T2 트랜잭션이 A 레코드를 변경합니다. 2에서 4가 아닌 1에서 3으로, A 레코드의 T2 트랜잭션 버전이 3이라고 씁니다.

T1 트랜잭션이 롤백 될 때 T1 트랜잭션 버전 인 2가 A 레코드에 적용되지 않는지 여부는 중요하지 않습니다. 그 후 T2 트랜잭션이 커밋되면 T2 트랜잭션 버전 인 3이 A ​​레코드에 적용됩니다. T1 트랜잭션이 T2 트랜잭션 이전에 커밋되면 A 레코드가 2로 변경된 다음 T2 트랜잭션 커밋시 3으로 변경됩니다. 최종 데이터베이스 상태는 다른 트랜잭션에 영향을주지 않고 각 트랜잭션을 독립적으로 실행하는 상태와 동일합니다. 따라서 ACID 속성을 만족합니다. 이 방법을 MVCC (Multi-version concurrency control)라고합니다.

MVCC는 메모리의 오버 헤드 증가 (동일한 데이터의 다른 버전을 유지해야하기 때문에) 및 계산 (REPETEABLE_READ 수준에서는 업데이트를 잃을 수 없으므로 Hiberate와 같은 데이터 버전을 확인해야 함)의 비용으로 동시 수정을 허용합니다. Optimistick Locking 과 함께 합니다.)

2PL 트랜잭션 격리 수준에서 다음을 제어합니다 .

  • 데이터를 읽을 때 잠금이 수행되는지 여부 및 요청 된 잠금 유형.

  • 읽기 잠금이 유지되는 기간입니다.

  • 다른 트랜잭션에 의해 수정 된 행을 참조하는 읽기 작업 여부 :

    • 행에 대한 독점 잠금이 해제 될 때까지 차단하십시오.

    • 문이나 트랜잭션이 시작될 때 존재했던 행의 커밋 된 버전을 검색합니다.

    • 커밋되지 않은 데이터 수정을 읽습니다.

트랜잭션 격리 수준을 선택해도 데이터 수정을 보호하기 위해 획득 한 잠금에는 영향을주지 않습니다. 트랜잭션은 해당 트랜잭션에 대해 설정된 격리 수준에 관계없이 항상 수정하는 모든 데이터에 대해 배타적 잠금을 얻고 트랜잭션이 완료 될 때까지 해당 잠금을 유지합니다. 읽기 작업의 경우 트랜잭션 격리 수준은 주로 다른 트랜잭션에 의해 수정 된 영향으로부터 보호 수준을 정의합니다.

격리 수준이 낮 으면 많은 사용자가 동시에 데이터에 액세스 할 수있는 능력이 향상되지만 더티 읽기 또는 업데이트 손실과 같은 동시성 효과의 수가 증가합니다 .

SQL Server의 잠금과 격리 수준 간의 관계에 대한 구체적인 예 (READ_COMMITTED_SNAPSHOT = ON 인 READ_COMMITED를 제외하고 2PL 사용)

  • READ_UNCOMMITED : 다른 트랜잭션이 현재 트랜잭션에서 읽은 데이터를 수정하지 못하도록 공유 잠금을 실행하지 마십시오. READ UNCOMMITTED 트랜잭션은 현재 트랜잭션이 수정되었지만 다른 트랜잭션에 의해 커밋되지 않은 행을 읽지 못하게하는 배타적 잠금에 의해 차단되지 않습니다. [...]

  • READ_COMMITED :

    • READ_COMMITTED_SNAPSHOT이 OFF (기본값)로 설정된 경우 : 공유 잠금을 사용하여 현재 트랜잭션이 읽기 작업을 실행하는 동안 다른 트랜잭션이 행을 수정하지 못하도록합니다. 공유 잠금은 또한 다른 트랜잭션이 완료 될 때까지 다른 트랜잭션에 의해 수정 된 행을 읽지 못하도록 명령문을 차단합니다. [...] 다음 행이 처리되기 전에 행 잠금이 해제됩니다. [...]
    • READ_COMMITTED_SNAPSHOT가 ON으로 설정된 경우 데이터베이스 엔진은 행 버전 관리를 사용하여 문 시작시 존재했던 데이터의 트랜잭션 적으로 일관된 스냅 숏을 각 문에 제공합니다. 잠금은 다른 트랜잭션에 의한 업데이트로부터 데이터를 보호하는 데 사용되지 않습니다.
  • REPETEABLE_READ : 공유 잠금은 트랜잭션의 각 문에서 읽은 모든 데이터에 적용되며 트랜잭션이 완료 될 때까지 유지됩니다.

  • SERIALIZABLE : 범위 잠금은 트랜잭션에서 실행되는 각 문의 검색 조건과 일치하는 키 값 범위에 배치됩니다. [...] 범위 잠금은 트랜잭션이 완료 될 때까지 유지됩니다.


5

잠금은 항상 DB 수준에서 수행됩니다.

Oracle 공식 문서 :-트랜잭션 중 충돌을 피하기 위해 DBMS는 트랜잭션에서 액세스하는 데이터에 대한 다른 사용자의 액세스를 차단하는 메커니즘 인 잠금을 사용합니다. (각 문이 트랜잭션 인 자동 커밋 모드에서는 하나의 문에 대해서만 잠금이 유지됩니다.) 잠금이 설정된 후에는 트랜잭션이 커밋되거나 롤백 될 때까지 계속 유지됩니다. 예를 들어 DBMS는 업데이트가 커밋 될 때까지 테이블의 행을 잠글 수 있습니다. 이 잠금의 효과는 사용자가 더티 읽기, 즉 값이 영구적으로 설정되기 전에 읽는 것을 방지하는 것입니다. (커밋되지 않은 업데이트 된 값에 액세스하는 것은 해당 값이 이전 값으로 롤백 될 수 있기 때문에 더티 읽기로 간주됩니다. 나중에 롤백 된 값을 읽으면 잘못된 값을 읽게됩니다. )

잠금 설정 방법은 트랜잭션 격리 수준이라고하는 것에 의해 결정되며, 트랜잭션을 전혀 지원하지 않는 것부터 매우 엄격한 액세스 규칙을 적용하는 트랜잭션을 지원하는 것까지 다양합니다.

트랜잭션 격리 수준의 한 가지 예는 TRANSACTION_READ_COMMITTED이며, 커밋 된 후까지 값에 액세스 할 수 없습니다. 즉, 트랜잭션 격리 수준이 TRANSACTION_READ_COMMITTED로 설정된 경우 DBMS는 더티 읽기가 발생하지 않도록합니다. 연결 인터페이스에는 JDBC에서 사용할 수있는 트랜잭션 격리 수준을 나타내는 5 개의 값이 포함되어 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.