일단 말씀해 주신 내용은 상당히 중요한 정보이고, 유용한 정보입니다. 감사드립니다. 그리고 아래 답변을 보니 확실히 conn.begintrans 로 transaction 을 시작하는 것과 BEGIN WORK 로 transaction 을 시작하는 것에는 차이가 나는 것 같습니다.
TRANSACTION 을 실행시 transaction 이 어느 정도로 독립적으로 운영되는 가 하는 것은 DBMS 를 설계한 사람의 policy 에 따라 많이 달라 질수 있다고 생각합니다. 대표적으로 isolation level 을 규정할 수 있는데 이 isolation level 이 transaction 을 실행에 상당한 영향을 미친다고 생각합니다. (자세한 것은 메뉴얼을 참조하시기 바랍니다. 실제로 SQL92 에서는 4종류의 isolation level 을 정의하고 있으며, PostgreSQL 의 경우 이중 두 level 의 isolation level 을 지원합니다.)
님의 글을 읽고 개인적으로 생각되는 바는 transaction을 처리하는 방법이 ODBC 에서 하는 것과 PostgreSQL 의 DBMS 에서 처리하는 것이 서로 다른 방법을 사용하는 것이 아닌가 하는 것입니다. 정확히 ODBC 프로그래밍 경험이 없어 확답할 수는 없지만 그 결과에 차이가 난다는 점에서 그럴수도 있겠다는 생각이 듭니다.
다른 문제는 아래 님의 글을 읽으면서 생각해 보기로 하겠습니다. 그 글 아래에 개인적인 생각을 달아 보도록 하겠습니다.
>>어떤생각 님께서 쓰시길<<
:: 먼저 결과부터 말하면
:: ODBC관리자에서 내리는 Lock 명령은 실행되지 않는다. 입니다.
::
:: 즉,
:: conn.open (ODBC관리자에 새로운 연결을 생성)
:: conn.begintrans (트랜잭션 시작)
:: conn.execute "lock table test in share mode" (Lock 명령 실행)
:: conn.execute "insert...." (insert 명령 실행)
:: conn.execute "delete ...." (delete 명령 실행)
:: conn.committrans (트랜잭션 완료)
:: conn.close (ODBC 연결해제)
::
:: 이렇게 실행하면 Lock이 걸리지를 않습니다. 중간에 다른 insert문을 다른
:: 프로세스에서 실행하면 실행이 되는 거지요. 하지만 commit할때 중간에
:: 끼어든 insert명령으로 인하여 생긴 레코드가 원래 transaction시작시에는
:: 없던 것이었기 때문에 commit되는 순간 사라져버립니다. 그래서
:: 데이타베이스 무결성은 유지됩니다. (흠 이러면 안되는데... 쩝)
이상하군요. 그렇던가요. 만약 transaction level 이 serializable isolation level 로 설정되어 있는 상태라면 동시에 실행중인 다른 uncommitted transaction 이 존재하는 경우, 후에 실행중인 transaction 에서 update/insert 등의 writing 을 요구하는 작업은 기존의 transaction 이 commit/rollback 하기까지 대기하게 되어 있습니다.
::
:: 하여간 이렇게 하면 안되지만 다음처럼하면
::
:: conn.open (ODBC관리자에 새로운 연결을 생성)
:: conn.execute "begin work" (트랜잭션 시작)
:: conn.execute "lock table test in share mode" (Lock 명령 실행)
:: conn.execute "insert...." (insert 명령 실행)
:: conn.execute "delete ...." (delete 명령 실행)
:: conn.execute "commit work" (트랜잭션 완료)
:: conn.close (ODBC 연결해제)
::
:: Lock이 실행됩니다. Lock table문이 실행된 이후에 다른 프로세스에서
:: insert나 delete등의 문을 실행 하면 table이 Lock이 걸려있기 때문에
:: insert문이 실행되지 않고 대기중의 상태로 들어갑니다. lock이
:: 걸리는 것이지요.
::
:: 그런데 이상한것은 이 Lock이 commit이 될때까지 유지되는 것이 아니라
:: lock명령 다음의 insert문이 실행되면 풀려버립니다.
:: 즉, 트랜잭션실행
:: /> lock으로 테이블을 잠군다.
:: /> 다른프로세스에서 insert문을 실행하면 대기 상태로 들어간다.
:: /> lock다음의 insert문을 실행한다.
:: /> 그러면 Lock이 풀리고 대기상태의 다른 insert문이 실행된다.
:: /> lock다음다음줄의 delete문을 실행한다.
:: /> commit을 실행하면 중간에 끼어든 insert문에 의한 새로운 레코드는
:: 없어진다. 의 동작이 발생하게 됩니다.
:: 이상하죠...^^
그렇군요. 정말 이상하군요 /./;
위의 로직과의 차이점은 connection 을 열어 준후에 begin work 로 하나의 트랜젝션을 열어 주었다는 것만이 차이점인데 말이죠 /./
:: 또 다른 이상한점.
:: 트랜잭션실행
:: /> lock으로 테이블을 잠군다.
:: /> 다른프로세스에서 begin work을 실행
:: /> 다른 프로세스에서 lock으로 테이블을 다시 잠군다.
:: (그러면 원래 lock이 걸려 있으니까 두번째 lock이 걸리지 않고 대기
:: 할줄 알았는데 의외로 두번째 Lock이 걸리네요...흠)
:: /> 원래 프로세스에서 insert문을 실행하면 두번째 Lock때문에 insert가
:: 실행되지 않고 대기 상태로 들어간다. (에구 정말 이상하다)
:: /> 다른 프로세스(두번째 Lock을 건)에서 insert문을 실행한다. 그러면
:: deadlock detected message가 나오고 이 트랜잭션이 실패했다고
:: 나오는군요. 그러면서 두번째 Lock이 풀립니다. (이건 또 원래의 Lock
:: 때문인가 보죠...)
:: /> 그러면 대기상태의 원래 insert문이 실행된다.
:: /> 그리고 다음의 delete문을 실행한다.
:: /> commit을 실행된다.
:: 의 동작이 발생하게 됩니다.
:: 더 이상하죠...^^ 원래 Lock이 걸려 있으면 그 다음 Lock을 걸려고 하면
:: 충돌하여 대기상태로 들어가게 되는 것 아닌가요? 원래 Lock이 풀릴때까지...
당연히 그렇게 되어야 할 것 같은데 말이죠. 그런데 문제는 현재 실행한 LOCK 의 레벨이 share mode 로 걸려 있다는 것이죠. 이것을 EXCLUSIVE mode 로 한번 테스트를 해 보면 어떨까요. 아마도 두번째 lock 의 시도가 실패하지 않을까 싶네요.
그런데 이런 장난 치다가는 가끔 deadlock 에 빠지는 경우가 있겠지요. 하지만 PostgreSQL 의 경우 이에 대한 대비는 어느 정도 되어 있는 것 같으니 한번 테스트 해 보세요. :/)
::
:: 제가 원래 생각했던 대로라면
:: 원래 프로세스에서 트랜잭션을 시작한다.
:: /> lock을 건다. (그러면 이후에 다른 프로세스에서 오는 모든 lock이나 insert등의 명령이 대기상태
:: 에 들어간다.)
:: /> 명령들을 모두 실행한다.
:: /> commit을 한다. 그러면 lock이 풀린다.
:: /> 이제 대기상태에 있던 다른 프로세스 명령들이 실행된다.
:: 의 동작이 일어나야 하는거 아닌가요?
::
:: 에구 제가 잘못알고 있는점이 있다면 설명을 부탁드립니다. Lock이 혹시 유지 시간을 갖구있나?... 쩝.
위의 모든 문제들이 아마도 ODBC 드라이브에서 deadlock 을 처리하는 과정의 차이에서 발생하는 것이 아닌가 싶습니다. 실제로는 ODBC 드라이버에서 begintrans 로 접속을 시켜도 혹시 그냥 단순한 connection open 만 하는 것은 아닐까요? 이 부분은 저가 정확히 모르겠습니다. 한번 확인해 보시기 바랍니다. 이 부분은 저가 좀더 공부를 해야 정확한 답변이 될 것 같습니다. 혹시 추가적인 정보를 얻게 되면 posting 해 주시면 감 사드리겠습니다.
|