나는 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 개의 동시 프로세스 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에서도 격리 수준을 설정할 수 있습니다.
- MySQL 격리 수준 ,
- SQL Server 격리 수준
- Informix 격리 수준 (개인 참고 :
SET ISOLATION TO DIRTY READ
문장을 잊지 않을 것 입니다.)
그리고 계속해서 …
답변
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 : 범위 잠금은 트랜잭션에서 실행되는 각 문의 검색 조건과 일치하는 키 값 범위에 배치됩니다. […] 범위 잠금은 트랜잭션이 완료 될 때까지 유지됩니다.
답변
잠금은 항상 DB 수준에서 수행됩니다.
Oracle 공식 문서 :-트랜잭션 중 충돌을 피하기 위해 DBMS는 트랜잭션에서 액세스하는 데이터에 대한 다른 사용자의 액세스를 차단하는 메커니즘 인 잠금을 사용합니다. (각 문이 트랜잭션 인 자동 커밋 모드에서는 하나의 문에 대해서만 잠금이 유지됩니다.) 잠금이 설정된 후에는 트랜잭션이 커밋되거나 롤백 될 때까지 계속 유지됩니다. 예를 들어 DBMS는 업데이트가 커밋 될 때까지 테이블의 행을 잠글 수 있습니다. 이 잠금의 효과는 사용자가 더티 읽기, 즉 값이 영구적으로 설정되기 전에 읽는 것을 방지하는 것입니다. (커밋되지 않은 업데이트 된 값에 액세스하는 것은 해당 값이 이전 값으로 롤백 될 수 있기 때문에 더티 읽기로 간주됩니다. 나중에 롤백 된 값을 읽으면 잘못된 값을 읽게됩니다. )
잠금 설정 방법은 트랜잭션 격리 수준이라고하는 것에 의해 결정되며, 트랜잭션을 전혀 지원하지 않는 것부터 매우 엄격한 액세스 규칙을 적용하는 트랜잭션을 지원하는 것까지 다양합니다.
트랜잭션 격리 수준의 한 가지 예는 TRANSACTION_READ_COMMITTED이며, 커밋 된 후까지 값에 액세스 할 수 없습니다. 즉, 트랜잭션 격리 수준이 TRANSACTION_READ_COMMITTED로 설정된 경우 DBMS는 더티 읽기가 발생하지 않도록합니다. 연결 인터페이스에는 JDBC에서 사용할 수있는 트랜잭션 격리 수준을 나타내는 5 개의 값이 포함되어 있습니다.