잠금과 동시성
이번에 드릴 이야기는 잠금과 동시성이라는 이야기 입니다.
동시성이란 것을 가지고.. SQL서버의 중요한 isolation level 이라는 이야기까지
드리게 되지요.
천천히 이야기를 진행해 보도록~~~ 하겠습니다. ^_^
동시성이란 것은 별 내용이 아닙니다.
A라는 사용자와 B라는 사용자가 있구요...
A라는 사용자는 이전에 보셨던 titles 테이블의 가격을 *2 하고 있으며
B라는 사용자는 읽으려 합니다.
이때 잠금이 걸려서 - 걸려야만 여러 문제를 해결 가능 했지요? - B사용자는 읽을 수
없었습니다.. 하지만.. B라는 사용자는 이런 잠금이 걸려 있더라도
깨고 들어가서 데이터를 읽고 싶었던 것입니다.
그래서 고민을 해 보니... isolation level을 줄 수 있는 것입니다.
혹시나 돌아가고 있는 쿼리가 있다면.. 모두 끄시구요..
다음을 한번더 수행해 보도록 하지요.
use pubs
go
--가격 * 2
begin tran
update titles set price = price * 2
--하나의 창을 더 오픈한다.
--파일 -> 연결을 하고 같은 서버에 접속한다.
use pubs
go
--데이터 조회
select * from titles
--조회가 불가하다.
--하나의 창을 더 오픈한다.
--파일 -> 연결을 하고 같은 서버에 접속한다.
use pubs
go
set transaction isolation level read uncommitted
select * from titles
--또는
select * from titles with(nolock)
어떠세요? 데이터가 읽어 집니다. ^_^
자.. 데이터를 자알~~ 읽었습니다만~~~
맨 처음의 update 쿼리 창으로 다시 돌아오신후..
rollback tran 을 하세요.
그러면 데이터는? *2를 하기 전의 상태로 되돌아 갔습니다. ^_^
그럼 저렇게 뭔지 모르겠지만 기인~~ set transaction isolation level read uncommitted
라고 붙여서 날린 쿼리의 결과는 뭐지요?
- 네 맞습니다. 잘못된 데이터를 불러온 것입니다.
이것은 양극화 된 이야기 입니다.
게시판 로직에서.. 조회수라는 부분이 있습니다.
그 쿼리는 보통 이렇지요..
update 게시판 set 컬럼 = 컬럼 + 1 where 키값컬럼 = 조건
이렇게 update로 잠금을 만들고 조회수를 + 1시키지요. ^_^
저게 뭐.. 금방 끝나는 건데 신경 안쓰면 되지 않냐??? 라고 하실지 모르지만..
동시접속자가 한 만명정도 되는.. - 모사이트를 생각해 보세요.
글하나가 올라가게 되면.. 수만명의 사용자가 동시에 와~~ 하고 달라붙어서
게시글을 읽는 부분으로요... 이때 대부분의 사용자는 게시글 하나에 달라붙게 되며
계속 조회수 + 1 때문에 게시글을 보려는 사람은 대기할 수 있습니다.
ADO로 만들어진 ASP사이트역시 마찬가지 이지요. - 자동 트랜잭션이 만들어 지기 떄문에..
하지만 저렇게.. 게시글을 읽는 부분에서..
set transaction isolation level read uncommitted 으로 데이터를 읽는다면?
별 문제 없을 겁니다. - 잠금을 무시하고 데이터를 읽지만...
조회수가 +1이 되었냐 안되었냐는 문제가 아니라는 것이지요!!!
그렇다면 다른 상황으로 계좌 이체를 생각해 보세요. 돈과 관련되면 문제는 항상
심각해 집니다. 계좌 이체 중인 사용자가.. 자신의 계좌와 다른 사용자의 계좌를
조회하니.. 자신의 계좌에서는 1억이 빠져 나갔는데.. 다른 계좌에는 아직 안 들어간걸
보았다면? - 여러 정황으로 문제가 될 수 있다는 것입니다.
적절하게 저러한 NOLOCK을 이용하시면 득을 보실 수 있다는 의미지요.
참고로..
set transaction isolation level read uncommitted 이 명령은..
연결된 세션 전체에 영향을 주게 되며 - ADO어플일 경우는 해당 쿼리가 수행되는 동안!
(NOLOCK)은 해당하는 쿼리에만 영향을 주게 됩니다.
그럼... 이제 저 isolation level에 대한 이야기를 풀어 보도록 하지요.
이는 한글로는 트랜잭션 격리 수준이라고 말합니다.
SET TRANSACTION ISOLATION LEVEL
{ READ COMMITTED
| READ UNCOMMITTED
| REPEATABLE READ
| SERIALIZABLE
}
과 같은 구문 정보를 가지게 되구요.
아울러... 각각의 해당하는 트랜잭션 격리 수준은 다음과 같습니다.
READ COMMITTED
데이터를 읽을 때는 공유 잠금이 유지되도록 해서 커밋되지 않은 데이터 읽기 가 이루어지지 않도록 지정하지만, 트랜잭션이 끝나기 전에 데이터가 변경되어 반복하지 않는 읽기 또는 팬텀 데이터가 만들어질 수 있습니다. 이 옵션은 SQL Server의 기본값입니다.
READ UNCOMMITTED
불필요한 읽기나 격리 수준 0을 구현합니다. 이렇게 하면 공유 잠금이 만들어지지 않고 단독 잠금이 무시됩니다. 이 옵션을 설정하면 커밋되지 않은 데이터나 불필요한 데이터를 읽을 수 있습니다. 데이터의 값이 변경될 수 있으며 트랜잭션이 끝나기 전에 데이터 집합에 행이 나타나거나 사라질 수도 있습니다. 이 옵션은 트랜잭션에서 모든 SELECT 문의 모든 테이블에 NOLOCK을 설정하는 것과 같습니다. 네 가지 격리 수준 중 제한이 가장 적습니다.
REPEATABLE READ
쿼리에서 사용되는 모든 데이터에 잠금을 배치해 다른 사용자가 데이터를 업데이트할 수 없도록 하지만, 다른 사용자가 데이터 집합에 새 허위 행을 삽입해 현재 트랜잭션의 이후 읽기에 포함될 수 있도록 합니다. 병행성이 기본 격리 수준보다 낮기 때문에 필요할 때만 이 옵션을 사용하도록 하십시오.
SERIALIZABLE
데이터 집합에 범위 잠금을 배치해 트랜잭션이 완료될 때까지 다른 사용자가 행을 업데이트하거나 데이터 집합에 삽입할 수 없도록 합니다. 네 가지 격리 수준 중 제한이 가장 많습니다. 병행성이 더 낮기 때문에 필요할 때만 이 옵션을 사용하도록 하십시오. 이 옵션은 트랜잭션의 모든 SELECT 문의 모든 테이블에 HOLDLOCK을 설정하는 것과 같습니다.
이런 상황이 나오게 됩니다. - 상세한 정보를 원하신다면 온라인 도움말을 참고하세요.
SQL서버를 사용하시면서.. 기본은 READ Committed 입니다.
그리고 READ uncommitted를 위와 같은 게시글 정도에서 종종 사용하시게 될 것이구요.
끝으로 SERIALIZABLE인데요. 이 옵션을 설명 드리고 싶어서.. 저렇게 주저리 주저리
적은 것입니다.
많은 분들이 최근 VB로 COM구성요소를 생성하고 사용하는데요..
이렇게 MTSTransactionMode를 잡아 주실 겁니다.
여기서 일반적인 데이터를 조회하는 모듈에서는? 1 - NOTransactions 를 사용하실 것이며
데이터를 수정하는 부분에서는 2- RequiresTransaction 을 이용하라고 배우실 겁니다.
이곳의 2- RequiresTransaction을 설정하시게 되면 DB차원에서는 저 트랜잭션 격리수준이
SERIALIZABLE로 잡히게 됩니다. - 무지막지하게 쎈~~ 녀석이 되지만.. 모 좋습니다.
그런데.. 문제는~~ 대부분의 분들이..
클래스 모듈을 하나로만 생성하시고.. 데이터를 조회하는 부분이나 수정하는 부분을
하나의 클래스에서 모두 수행하게 생성합니다. 즉 - SELECT 쿼리를 수행하는 모듈 역시
SERIALIZABLE한 격리수준으로 처리가 된다는 것이지요. 혼자서 개발을 하고 작업을
한다면 문제가 없지만.. 실제 프러덕션 서버에 적용을 시킨 후에는 문제가 될 수 있지요.
그러면 구성요소 만들때 어떻게 하라는 거냐 트랜잭션을 쓰지 말라는거냐?
간단합니다.
이렇게 데이터를 조회하는 모듈과 수정하는 모듈을 분리하고 처리하는 것입니다.
Modify에는 당연히 트랜잭션 필요로 설정하고.. 데이터 조회 모듈인 Query에서는
트랜잭션 사용안함인 1로 처리하시는 것이지요. 이렇게 해당하는 모듈을 분리해서
처리하시면 됩니다.
이 이야기를 드리고 싶어서... 대단히 긴 여정을 밟아 왔군요. ^_^
많은 분들은 아는 이야기겠지만.. 여러군데에서 저런 문제를 사용하는 개발자
분들을 보아 왔기 때문에.. 이부분을 꼬옥~ 이야기 드리고 싶었습니다.
자.. 동시성에 대한 이야기는 맨 처음에 쬐금 나오고.. isolation level에 대한 이야기만
풀게 되는군요. ^_^
그외의 트랜잭션 격리 수준들은 제 경험상으로도 거의 사용하실 일이 없으실 것이구요.
read uncommitted부분과 SERIALIZABLE 한 부분.. 그리고 기본 모드인
read committed 부분만 참고 하시길 바랍니다. ^_^
상세한 샘플은.. 사실 제가 사용한 적이 거의 없으니.. 다른분들도 거의 사용 안하실
거라고 혼자만의 생각을 하면서.. -_-;; 이만 넘어가도록 하지요.
혹시.. 위의 세개가 아닌 다른 트렌젝션 격리 수준을 사용하시는 분들은??
꼬옥 자유 게시판에.. 정황이야기 적어 주시면 감사하겠습니다. -
샘플 만들기 어렵습니다. T.T;;;
출처:
http://www.comqna.net/bbs/tb.php/database/17/ccf9de326bdfc5d2a41242ae3e69eae8