낙관적 잠금과 비관적 잠금의 차이점을 이해합니다. 이제 내가 일반적으로 하나를 사용할 때 누군가가 나에게 설명 할 수 있습니까?
그리고이 질문에 대한 답변은 저장 프로 시저를 사용하여 쿼리를 수행하는지 여부에 따라 변경됩니까?
그러나 확인하기 만하면 낙관적 의미는 "읽는 동안 테이블을 잠그지 마십시오"를 의미하고 비관적 의미는 "읽는 동안 테이블을 잠그십시오"를 의미합니다.
낙관적 잠금과 비관적 잠금의 차이점을 이해합니다. 이제 내가 일반적으로 하나를 사용할 때 누군가가 나에게 설명 할 수 있습니까?
그리고이 질문에 대한 답변은 저장 프로 시저를 사용하여 쿼리를 수행하는지 여부에 따라 변경됩니까?
그러나 확인하기 만하면 낙관적 의미는 "읽는 동안 테이블을 잠그지 마십시오"를 의미하고 비관적 의미는 "읽는 동안 테이블을 잠그십시오"를 의미합니다.
답변:
낙관적 잠금 은 레코드를 읽고 버전 번호 (날짜, 타임 스탬프 또는 체크섬 / 해시를 포함하는 다른 방법)를 기록하고 레코드를 다시 쓰기 전에 버전이 변경되지 않았는지 확인하는 전략입니다. 레코드를 다시 쓰면 버전의 업데이트를 필터링하여 최신 상태인지 확인합니다. (즉, 버전을 확인하고 레코드를 디스크에 쓸 때 사이에 업데이트되지 않았습니다) 한 번에 버전을 업데이트하십시오.
레코드가 더러 우면 (즉, 다른 버전과 다름) 트랜잭션을 중단하고 사용자가 다시 시작할 수 있습니다.
이 전략은 세션의 데이터베이스에 대한 연결을 반드시 유지할 필요가없는 대용량 시스템 및 3 계층 아키텍처에 가장 적합합니다. 이 상황에서는 연결이 풀에서 이루어 지므로 클라이언트가 실제로 데이터베이스 잠금을 유지할 수 없으며 한 액세스에서 다음 액세스로 동일한 연결을 사용하지 않을 수 있습니다.
비관적 잠금 은 레코드가 끝날 때까지 독점 사용을 위해 레코드를 잠그는 것입니다. 낙관적 잠금보다 무결성이 훨씬 뛰어나지 만 교착 상태 를 피하려면 응용 프로그램 디자인에주의해야합니다 . 비관적 잠금을 사용하려면 일반적으로 2 계층 클라이언트 서버 응용 프로그램 에서와 같이 데이터베이스에 직접 연결 하거나 연결과 독립적으로 사용할 수있는 외부에서 사용 가능한 트랜잭션 ID가 필요합니다.
후자의 경우 TxID로 트랜잭션을 연 다음 해당 ID를 사용하여 다시 연결합니다. DBMS는 잠금을 유지하고 TxID를 통해 세션을 다시 선택할 수 있습니다. 이는 2 단계 커밋 프로토콜 (예 : XA 또는 COM + 트랜잭션 )을 사용하는 분산 트랜잭션이 작동하는 방식입니다.
많은 충돌이 예상되지 않는 경우 낙관적 잠금이 사용됩니다. 정상적인 작동에는 비용이 덜 들지만 충돌이 발생하면 거래가 중단 될 때 더 높은 가격을 지불하여 해결합니다.
비관적 잠금은 충돌이 예상 될 때 사용됩니다. 동기화를 위반하는 트랜잭션은 단순히 차단됩니다.
적절한 잠금 메커니즘을 선택하려면 읽기 및 쓰기 양을 추정하고 그에 따라 계획해야합니다.
낙관론은 읽는 동안 아무것도 바뀌지 않을 것이라고 가정합니다.
비관론은 무언가가 그것을 잠그고 있다고 가정합니다.
데이터를 완벽하게 읽을 필요가없는 경우에는 낙관적입니다. 이상한 '더러운'을 읽을 수는 있지만 교착 상태 등이 발생할 가능성은 훨씬 적습니다.
대부분의 웹 응용 프로그램은 더티 읽기로 괜찮습니다. 드물기는하지만 데이터가 다음 재로드에서 정확하게 계산되지는 않습니다.
많은 금융 거래와 같이 정확한 데이터 작업을 위해서는 비관적입니다. 표시되지 않은 변경없이 데이터를 정확하게 읽는 것이 중요합니다. 추가 잠금 오버 헤드가 그만한 가치가 있습니다.
아, 그리고 Microsoft SQL 서버는 기본적으로 페이지 잠금으로 기본 설정되어 있습니다. 행 잠금이 더 정확하지만 훨씬 느립니다. 읽는 동안 교착 상태를 피하기 위해 트랜잭션을 읽기 커밋 또는 잠금 해제로 설정하는 것이 좋습니다.
이미 말한 것 외에도 :
optimistic
잠금 예측의 비용으로 동시성을 개선하는 경향이있다.Pessimistic
잠금은 동시성을 줄이는 경향이 있지만 더 예측 가능합니다. 당신은 돈 등을 지불 ...충돌을 다룰 때 두 가지 옵션이 있습니다.
이제 다음과 같은 Lost Update 예외를 고려해 보겠습니다 .
손실 된 업데이트 이상은 읽기 커밋 된 격리 수준 에서 발생할 수 있습니다 .
위의 다이어그램에서 Alice는 자신이 40 명을 인출 할 수 있다고 생각 account
하지만 Bob이 계정 잔액을 변경 한 사실을 알지 못했지만이 계정에는 20 개만 남았습니다.
비관적 잠금은 계정에서 공유 또는 읽기 잠금을 수행하여 Bob이 계정을 변경하지 못하도록하여이 목표를 달성합니다.
위의 다이어그램에서 Alice와 Bob은 account
두 사용자가 모두 읽은 테이블 행 에 대한 읽기 잠금을 획득합니다 . 데이터베이스는 반복 가능한 읽기 또는 직렬화 가능을 사용할 때 SQL Server에서 이러한 잠금을 획득합니다.
Alice와 Bob은 모두 account
PK 값 이 인을 읽었으므로 1
한 사용자가 읽기 잠금을 해제 할 때까지 둘 다 변경할 수 없습니다. 쓰기 작업에는 쓰기 / 독점 잠금 획득이 필요하고 공유 / 읽기 잠금은 쓰기 / 독점 잠금을 방지하기 때문입니다.
Alice가 트랜잭션을 커밋하고 읽기 잠금이 account
행에서 해제 된 후에 만 Bob UPDATE
이 재개하고 변경 사항을 적용합니다. Alice가 읽기 잠금을 해제 할 때까지 Bob의 UPDATE는 차단됩니다.
데이터 액세스 프레임 워크가 기본 데이터베이스 비관적 잠금 지원을 사용하는 방법에 대한 자세한 내용은 이 기사를 확인 하십시오 .
낙관적 잠금은 충돌이 발생하지만 버전이 변경됨에 따라 Alice의 UPDATE를 적용 할 때 충돌을 감지합니다.
이번에는 추가 version
열이 있습니다. version
열 때마다 업데이 트를 증가 또는 DELETE가 실행되고, 그것은 또한 UPDATE 및 DELETE 문장의 WHERE 절에 사용됩니다. 이 작업 version
을 수행하려면 UPDATE 또는 DELETE를 실행하기 전에 SELECT를 발행하고 현재를 읽어야합니다. 그렇지 않으면 WHERE 절에 전달하거나 증가시킬 버전 값을 알 수 없습니다.
관계형 데이터베이스 시스템은 클라이언트가 일반적으로 터미널을 통해 메인 프레임에 연결할 때 70 년대 후반 80 년대 초에 등장했습니다. 이것이 데이터베이스 시스템이 세션 설정과 같은 용어를 정의하는 이유입니다.
오늘날 인터넷을 통해 더 이상 동일한 데이터베이스 트랜잭션의 컨텍스트에서 읽기 및 쓰기를 실행하지 않으며 ACID로는 더 이상 충분하지 않습니다.
예를 들어 다음 사용 사례를 고려하십시오.
낙관적 잠금이 없으면 데이터베이스 트랜잭션이 Serializable을 사용하더라도이 손실 된 업데이트가 발견되지 않았을 것입니다. 읽기 및 쓰기가 별도의 HTTP 요청으로 실행되므로 다른 데이터베이스 트랜잭션에서 실행되기 때문입니다.
따라서 낙관적 잠금 기능을 사용하면 사용자가 생각하는 시간도 포함 된 응용 프로그램 수준 트랜잭션을 사용할 때도 업데이트 손실을 방지 할 수 있습니다.
낙관적 잠금은 매우 유용한 기술이며, 커밋 된 읽기와 같이 덜 엄격한 격리 수준을 사용하거나 후속 데이터베이스 트랜잭션에서 읽기 및 쓰기가 실행될 때에도 제대로 작동합니다.
낙관적 잠금의 단점은를 포착 할 때 데이터 액세스 프레임 워크에 의해 롤백이 트리거되어 OptimisticLockException
현재 실행중인 트랜잭션에 의해 이전에 수행 한 모든 작업이 손실된다는 것입니다.
경합이 많을수록 충돌이 많으며 거래 중단 가능성이 높아집니다. 테이블 행과 인덱스 레코드가 모두 포함될 수있는 현재 보류중인 모든 변경 사항을 되돌려 야하므로 데이터베이스 시스템에 대한 롤백 비용이 많이들 수 있습니다.
이러한 이유로 트랜잭션이 롤백 될 가능성을 줄이기 때문에 충돌이 자주 발생하는 경우 비관적 잠금이 적합 할 수 있습니다.
PESSIMISTIC_FORCE_INCREMENT
있습니다.
비관적 잠금이 더 나은 선택이 될 경우를 한 번 더 생각할 것입니다.
낙관적 잠금을 위해 데이터 수정의 모든 참가자는 이러한 종류의 잠금 사용에 동의해야합니다. 그러나 누군가가 버전 열을 신경 쓰지 않고 데이터를 수정하면 낙관적 잠금의 전체 아이디어를 망칠 것입니다.
기본적으로 두 가지 가장 인기있는 답변이 있습니다. 첫 번째 는 기본적으로 말합니다
Optimistic에는 세션을 위해 데이터베이스에 대한 연결을 반드시 유지할 필요가없는 3 계층 아키텍처가 필요하지만 Pessimistic Locking은 레코드가 끝날 때까지 독점 사용을 위해 레코드를 잠글 때입니다. 데이터베이스에 직접 연결해야하는 낙관적 잠금보다 무결성이 훨씬 뛰어납니다.
잠금이 없기 때문에 낙관적 (버전 관리)이 빠르지 만 경합이 높을 때 (비관적) 잠금이 더 잘 수행되며 작업을 버리고 다시 시작하지 않고 작업을 방지하는 것이 좋습니다.
또는
낙관적 인 충돌이 발생할 때 낙관적 잠금이 가장 효과적입니다.
이 페이지에 수록 되어 있습니다.
"연결 유지"가 "낮은 충돌"과 어떻게 관련되어 있는지 설명하기 위해 대답을 만들었습니다.
어떤 전략이 가장 적합한 지 이해하려면 DB의 초당 트랜잭션이 아니라 단일 트랜잭션 기간에 대해 생각하십시오. 일반적으로 trasnaction을 열고 작업을 수행하고 트랜잭션을 닫습니다. 이것은 ANSI가 짧고 고전적인 트랜잭션으로 잠금을 피하기에 좋습니다. 그러나 많은 고객이 같은 방 / 좌석을 동시에 예약하는 티켓 예약 시스템을 어떻게 구현합니까?
오퍼를 탐색하고 사용 가능한 많은 옵션과 현재 가격으로 양식을 채우십시오. 시간이 많이 걸리고 옵션이 더 이상 사용되지 않을 수 있습니다. 액세스 한 데이터에 대한 잠금이 없었고 다른 사람이 더 민첩하고 다른 방식으로 액세스했기 때문에 양식을 작성하기 시작하고 "동의 함"버튼을 누르기 전에 유효하지 않은 모든 가격 모든 가격을 변경하고 새 가격으로 다시 시작해야합니다.
대신 모든 옵션을 잠글 수 있습니다. 이것은 비관적 인 시나리오입니다. 왜 짜증나는지 알 수 있습니다. 예약을 시작하고 담배를 피우는 한 명의 광대가 당신의 시스템을 무너 뜨릴 수 있습니다. 그가 끝내기 전에는 아무것도 예약 할 수 없습니다. 현금 흐름이 0으로 떨어집니다. 그렇기 때문에 현실적으로 낙관적 예약이 사용됩니다. 너무 오래 머무는 사람들은 더 높은 가격으로 예약을 다시 시작해야합니다.
이 낙관적 인 접근 방식에서는 읽은 모든 데이터를 기록해야하며 ( 반복 된 읽기 와 같이) 데이터 버전으로 커밋 포인트에 도달해야합니다 (현재 가격이 아닌이 견적에 표시된 가격으로 주식을 사고 싶습니다) ). 이 시점에서 ANSI 트랜잭션이 생성되어 DB를 잠그고 변경 사항이 없는지 확인하고 작업을 커밋 / 중단합니다. IMO는 Optimistic CC 와도 관련이있는 MVCC의 효과적인 에뮬레이션 이며 중단시 트랜잭션이 다시 시작된다고 가정합니다. 즉, 새 예약을합니다. 여기서의 거래에는 사용자의 결정이 포함됩니다.
MVCC를 수동으로 구현하는 방법을 이해하지 못했지만 재시작 옵션이있는 장기 실행 트랜잭션이 주제를 이해하는 열쇠라고 생각합니다. 내가 어딘가 잘못하면 나를 바로 잡으십시오. 나의 대답은 이 Alex Kuznecov 장 에서 동기를 부여 받았다 .
대부분의 경우 낙관적 잠금이 더 효율적이며 더 높은 성능을 제공합니다. 비관적 잠금과 낙관적 잠금 중에서 선택할 때 다음을 고려하십시오.
비관적 잠금은 업데이트가 많고 사용자가 데이터를 동시에 업데이트하려고 할 가능성이 높은 경우에 유용합니다. 예를 들어, 각 작업에서 한 번에 많은 수의 레코드를 업데이트 할 수 있고 (은행에서 매월 말에 모든 계정에이자 수입을 추가 할 수 있음) 두 응용 프로그램이 동시에 이러한 작업을 실행하는 경우 충돌이 발생합니다 .
비관적 잠금은 자주 업데이트되는 작은 테이블이 포함 된 응용 프로그램에서도 더 적합합니다. 이러한 소위 핫스팟의 경우 충돌이 발생할 가능성이 매우 높아 낙관적 잠금으로 인해 충돌하는 트랜잭션을 롤백 할 때 낭비가됩니다.
낙관 가능성은 충돌 가능성이 매우 낮은 경우에 유용합니다. 레코드는 많지만 사용자는 적거나 업데이트 및 읽기 유형 작업은 거의 없습니다.
낙관적 잠금의 사용 사례 중 하나는 응용 프로그램이 데이터베이스를 사용하여 스레드 / 호스트 중 하나가 작업을 '확보'하도록하는 것입니다. 이것은 정기적으로 저에게 유용한 기술입니다.
내가 생각할 수있는 가장 좋은 예는 여러 스레드가 작업을 동시에 요구하는 데이터베이스를 사용하여 구현 된 작업 대기열입니다. 작업의 상태가 'Available', 'Claimed', 'Completed'인 경우 db 쿼리는 "Set status = 'Claimed'where status = 'Available'과 같이 말할 수 있습니다. 여러 스레드가 이러한 방식으로 상태를 변경하려고하면, 더티 데이터로 인해 첫 번째 스레드를 제외한 모든 스레드가 실패합니다.
이것은 낙관적 잠금 만 사용하는 유스 케이스입니다. 따라서 "많은 충돌이 예상되지 않을 때 최적화 잠금이 사용된다"는 대안으로 충돌이 예상되지만 정확히 하나의 트랜잭션이 성공하기를 원하는 경우에도 사용할 수 있습니다.