FireBird Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
파이어버드 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
IBPhoenix
FireBird Main site
볼랜드포럼 광고 모집

FireBird FAQ
[53] Firebird 데이터 갱신과 Commit, Rollback
크레브 [kkol] 23286 읽음    2012-03-13 23:18
아래 내용은 델마당에 2007년쯤 올라온 질문이고 제가 궁금해 하던 내용입니다.
링크를 걸려고 하는데 이상하게 델마당 게시글의 절대 링크 주소를 가져올 수 가 없네요
페이스북에서 임프님이 답글을 달아주셨는데 다른 분들에게도 도움이 될까하여 여기로 옮깁니다.

--------------------------------------- 델마당 질문 -----------------------------------
[조건]
- 한개의 데이터를 여러 pc가 참조합니다.
- 데이터베이스는 파이어버드2.0입니다.
- 프로그램은 ibdatabase, ibtransaction, ibquery를 사용해서 조䟀, 입력, 수정, 삭제등의 작업을 하고 있습니다.
[문제점1]
- 위의 조건처럼 한 데이터 베이스를 여러 피씨가 참조하는 경우...
한쪽 pc에서 입력한뒤 다른쪽 pc에서 방금 입력한 자료를 조䟀해도 나타나지 않습니다.(일반 query는 상관 없다고 합니다. ibq
uery의 특성인가 봅니다.)
[문제점1에 대한 해결]
- 그래서...조䟀를 하기전에 ibtransaction.commit을 하도록 하였습니다.
- 일단 결과는 만족입니다. 언제 어떤 pc에서 조䟀하더라도 입력한 자료가 나타납니다.
[문제점2]
- 그런데... 항상 commit을 사용하니 한 창에 2~3개의 grid를 놓고 작업을 하면 commit하는 순간 모든 grid의 내용이 없어져
버립니다.
- 또, main form위에 sub폼을 열도록 하는경우 sub폼에서 commit을 사용하면 main폼의 grid내용도 없어져 버립니다.
- 그리고, 항상 조䟀하기전에 commit을 사용하니 이건 뭔가 말도안되는 삽질하는 기분이... 이건 아닌것 같습니다.
[질문]
그러면...
1. 고수님들은 server client 환경의 프로그램을 개발할때 어떤 방식으로 commit처리를 하시는지요?
2. 위의 문제처럼 한 창에 2~3개의 grid를 놓았을때는 또 어떻게 commit처리를 하십니까?
아... 지금이라도 ibquery를 버리고 bde의 query를 사용해야 하는지...
아무리 게시판을 검색해 봐도 위와 비슷한 내용의 질문은 있으나 딱부러진 결과는 없는것 같습니다.
죄송하지만 위와같은 문제점을 해결하셨거나 격어 보셨던 고수님들의 답변 바랍니다.





----------------------  임프님 답변   -----------------------------------------


그건 인터베이스/파이어버드의 좀 특이한 동작인데... 기본적으로 인터베이스 계열은 락 기반이 아니라 멀티버전으로 관리해서 그렇습니다. 무슨말이냐 하면, 인서트와 마찬가지로 셀렉트도 실행되는 순간 자체 트랜잭션을 갖게 됩니다. 실행중인 모든 트랜잭션들이 서로 충돌하지 않게 하기 위해, 모든 트랜잭션에는 연결한 데이터베이스에 대한 가상의 복사본 같은 게 생긴다고 보면 됩니다.

즉 인서트든 select든 실행되는 순간 자체 복사본을 가지고 작업을 하게 되기 때문에, A 연결에서 select를 처음 실행한 후엔 B 연결에서 insert나 delete를 하고 커밋을 하더라도 select를 실행했던 A 연결의 데이터베이스는 이미 기존의 복사본을 가지고 계속 동작하고 있기 때문에 B 연결의 insert, delete에 영향을 받지 않습니다.

이런 복사본에 대한 작업이 종료되는 시점은 짐작하시겠지만 트랜잭션이 종료되는 시점으로, 즉 commit이나 rollback을 하는 시점입니다. 그런데 select를 했던 A 연결에서는 B연결에서 insert를 했는지 안했는지 언제 하는지를 알 수가 없기 때문에, 간단한 해결책 하나는 select를 할 때마다 바로 rollback을 실행해버리는 겁니다. 그러면 언제 select를 하든 항상 최신 버전의 데이터베이스를 볼 수 있게 되죠.

그런데 여기서 문제는, (제 기억으로는) select한 후에 rollback이나 commit을 하는 순간 쿼리가 클로즈되어 버릴 겁니다. 즉 select하고 바로 rollback을 하면 당연히 데이터를 볼 수가 없게 되죠. 이걸 막기 위한 하나의 방법은, IBQuery를 DataSetProvider에 연결하고, 다시 ClientDataSet에 연결한 후 이 ClientDataSet에 올라온 데이터를 사용하는 겁니다.

자 이렇게 하면 네트워크상으로는 아니지만 논리적으로 3티어가 되었습니다. IBQuery가 2번째 미들 티어, ClientDataSet이 3번째 클라이언트 티어, 이렇게요. 이렇게 연결된 구조에서 ClientDataSet에서 오픈하면 간접적으로 연결된 IBQuery도 오픈이 되고 데이터가 보이겠죠. 그리고 IBQuery가 연결된 트랜잭션에서 바로 rollback을 해버리면 IBQuery는 닫히겠지만 ClientDataSet은 여전히 열려 있습니다. 그래서 ClientDataSet에 올라온 데이터는 유효하고 DBGrid에서도 계속 보이게 되죠.


다른 방법이 있는지도 모르겠습니다만, 제가 파이어버드로 애플리케이션 개발할 때는 이렇게 했었던 걸로 기억합니다. 최근 몇년간 애플리케이션에 파이어버드를 쓸 일은 없어서 기억이 희미하네요. 지금도 볼랜드포럼 서버에는 파이어버드를 쓰고 있지만, 웹이기 때문에 IBQuery에서 select를 한 다음 웹 응답 텍스트에 다 복사하는 과정이 있어서 그 이후에 바로 close, rollback하는게 보통이라 3티어 구조를 쓸 필요가 없거든요.
11시간 전 · 좋아요 취소 ·  1
박지훈 참 그리고.. 상용 컴포넌트인 IBDAC이나 UniDAC(둘다 같은 DevArt 제품이죠)에선 AutoCommit 속성이 추가되어 있어서 모든 SQL문을 실행할 때마다 자동으로 commit을 해주죠. 뭐 대단한 동작은 아니지만 쿼리문을 아주 많이 다룰 때는 귀찮은 일을 많이 덜 수 있습니다.

참고로, 그렇다고 해서 모든 SQL문마다 commit을 날리는 것은 성능상 아주 좋지 않게 됩니다. 데이터베이스에 레코드를 인서트하는 경우 insert 자체보다 commit에서 시간을 꽤 많이 잡아먹습니다. 간단히 테스트를 해보시면 아실 수 있는데, insert 하나마다 commit 하면서 10000 레코드를 인서트하는 경우, 10개마다, 100개마다, 10000개 모두 insert한 후에 commit하는 경우의 속도가 다 다릅니다. 당연히 한꺼번에 commit을 하는게 압도적으로 빠릅니다. 속도 차이가 수십배 납니다.

성능상 커밋을 몰아서 하는 게 낫다고 무조건 몰아서 하는 것도 좋지많은 않죠. 일단 커밋이 안된 데이터는 다른 연결에서 볼 수가 없는 데다, 커밋을 안한 상태에서 만약 PC가 갑자기 다운된다든지 하면 그사이 인서트했던 데이터는 날아가게 되죠. (당연한 동작입니다만) 그래서, 대량 인서트가 필요한 경우 개발하시는 애플리케이션의 성격과 용도에 따라 적당히 잘라가며 인서트하면 됩니다.

이성열님처럼 하드웨어 업계에서 일하시는 분들은 파이어버드를 로깅 용도로 사용하는 경우가 많이 있던데, 엄청나게 많은 데이터가 들어오는 경우 파이어버드에서 몰아서 commit하는 방식을 사용하면 짱입니다. 전에 제가 파이어버드를 로깅 엔진으로 쓸 때 테스트했던 결과로는, 대략 1천건 정도의 수준까지 모았다가 commit을 하면 적당했습니다. 그 이상은 성능상 그닥 큰 체감 차이가 나지 않더군요.
정인식 [isjoung]   2012-09-10 15:49 X
파워빌더를 사용하는 사람입니다.
위의 [문제점1]에 대한 내용은 파워빌더에서 나타나지 않고
다른 DB 즉, 오라클, MS SQL, MySQL, PostgreSQL 등과 동일하게 작동 하는 것 같습니다.
한 화면에 Grid 2-3개를 사용합니다.
까막.윤창희 [ggamagui]   2018-04-07 00:02 X
2007년의 질문이고, 2012년에 정리된 글이지만 현재에도 Firebird 를 다루는 분이 계시다면 도움이 될 수 있을 것 같아 뒤늦게라도 적어봅니다.


위 문제는 임프님께서 말씀하신 것처럼 IB/FB 의 특이성으로 발생하는 현상으로, 간단하게 세션을 분리하면 쉽게 해결할 수 있습니다.
세션은 각각 독립적으로 동작하므로 세션을 분리해서 사용하면 조회를 하든, 추가,수정,삭제를 하든 서로 영향을 끼치지 않으면서 처리할 수 있습니다.

* InterBase 컴포넌트를 사용한다고 보고요.

1. IBDatabase 컴포넌트 밑에 IBTransaction 을 두개를 사용합니다.
    조회용 Transaction : itrSearch
    추가, 수정, 삭제등의 데이터 처리용 Transaction : itrArrow

2. 각각의 용도에 맞게 Transaction 의 DefaultAction 과 AutoStopAction 설정을 합니다.
    itrSearch.DefaultAction    := TACommitRetaining;  -> Commit 을 하고 그 값을 유지.
    itrSearch.AutoStopAction := saRollback;  -> Exception 이 발생하면 Rollback.

    itrArrow..DefaultAction     := TACommit;
    itrArrow.AutoStopAction   := saNone;

3. 조회용으로 사용하는 IBQuery, IBStoredProc 등의 Transaction 속성은 itrSearch 를, 데이터 처리 용도는 itrArrow 로 설정합니다.

4. 조회 작업시는 그냥 사용을 하면 되고요.
    데이터 처리 작업시는 Transaction 을 걸고 사용하시면 됩니다.
    물론 Exception 은 필수로 있어야 겠죠. 상황에 따라 Commit 이나 Rollback 을 해야 하니까요.

* 위 설정처럼 사용을 하시면 아무 문제 없습니다.
* 아래는 2007년 당시에 볼포에 올라온 질문글에 대해 답변을 단 것입니다.
   아마 델마당에 질문을 하셨던 분이랑 같은 분의 글인 것 같네요.

    http://firebird.borlandforum.com/impboard/impboard.dll?action=read&db=fb_qna&no=2646

+ -

관련 글 리스트
53 Firebird 데이터 갱신과 Commit, Rollback 크레브 23286 2012/03/13
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.