[답변에 대한 답글입니다.] Trigger 이벤트 시점에 대해 질문드립니다.

by cubridtest posted Oct 31, 2019

* 질문 등록 시 다음의 내용을 꼭 기입하여 주세요.
OS
Window7 32bit, Linux 64bit 등
CUBRID Ver.
[cubrid_rel] 수행 결과
CUBRID TOOL Ver.
[도움말]-[버전정보] 확인
응용 환경(API)
java, php, odbc 등 입력

* CUBRID 응용 오류, SQL 오류 또는 SQL 튜닝 관련된 문의는 반드시 다음의 내용을 추가해 주세요. 비밀글이나 비밀 댓글도 가능합니다.
* 저희가 상황을 이해하고, 재현이 가능해야 알 수 있는 문제들이 많습니다. 가능한 정보/정황들을 부탁합니다.
에러 내용 및 재현 방법 재현 가능한 Source와 SQL
관련 테이블(인덱스, 키정보 포함) 정보 CUBRID 홈 디렉토리 아래 log 디렉토리 압축


-------------- 아래에 질문 사항을 기입해 주세요. ------------------------------------------------------------------------
안녕하세요~!

우선 친전할 답변 감사드리고 손수 테스트해주신점 너무 감사드려요.



말씀해주신 방법으로는 해결을 못했는데

우여곡절 끝에 뭐 해결은 했습니다.



다만 DEFERRED UPDATE 문에 약간의 버그가 있는것 같아서 말씀드립니다~!



제가 만드려고 했던 트리거는 

A db,  B db 양방향 동기화 트리거 였습니다.


즉 A db에서 insert,update,delete가 발생하면 B db에 즉각 반영합니다. 

반대로 B db에서 dml 실행시 A db에 즉각반영하는 트리거입니다.



A  db , B db 트리거는 동일 한 구문이며

트리거 안에 javaSp역시target이 되는 db의 url만 다를 뿐  동일한 클래스 파일입니다.


즉 서로가 서로를 물기 때문에 무한 루프를 방지하기 위해 

dml 실행 전 select로 상대 db에 해당 레코드에 대한 검증을 해야합니다.


또 말씀 해주신 방법대로 old ,new 상관명을 사용하면 

컬럼이 만약 10개라면 10개의 파라미터를 인자로 받아야 하기 때문에 상당히 비효율적이며


해당 javaSp는 해당 테이블 맞춤으로 밖에 사용하지 못합니다.

이것이 제가 굳이 select를 한 이유입니다.



여하튼  아래와 같이 CUBRIDOID 객체를 응용해서


create procedure ttt

deferred insert on test

execute call javasp(obj)


obj를 통째로 넘기는 javasp를 구현하긴 하였습니다.




다만 문제는 update할떄의 문제였습니다.


update javaSp로직은 대강


1)obj를 파라미터로 받는다

2)obj에서 기본키 추출

3)타겟이 되는 db에 기본키를 대입하여 해당 레코드 한줄을 불러온다.

4-1)불러온 레코드의 업데이트 컬럼의 값과 입력받은 obj의 업데이트 컬럼 값이 같다면 update완료로 간주하고 실행을 중지한다

4-2)컬럼 값이 다르다면 update를 진행한다.

5-1) javaSp 종료, Trigger 종료


대강 이런식의 로직입니다.



DEFERED 키워드가 커밋이 된 데이터에 대해서만 다루는것이라면

위에 로직은 문제 없이 돌아가야합니다.



이런식으로 한쪽 db에만 javaSp를 올리고 트리거를 등록한후 update를 발생시키면

상대 db에 잘 들어가있습니다. 


문제는


양쪽에 올리고 실행시키는 순간 무한루프에 빠져 lock에 걸립니다.



한줄한줄 로그를 찍어보며 확인해본결과


1) A DB에서 트리거가 발생하고 위에서 말한 4-2)단계를 진행 


2) B DB에서 동일 트리거가 발생하고 위에서 말한 4-1)단계로 가야하는데 가지 못하고 4-2)로 넘어감


    즉 DEFERED 키워드로 인해 A DB 트리거를 동작시킨 레코드가 COMMIT이 된 상태라면

    이 단계에서 업데이트 컬럼의 값이 같아져서 업데이트 실행을 중지해야하는데, 계속 다른걸로 간주됩니다. 즉 COMMIT이 되지 않은 상태라는거죠



제가 뭔가 하자가 있다고 말씀드리는 이유는


INSERT 트리거 역시 DEFERED 키워들 주었으며 위와 동일한 로직입니다.


업데이트 시간컬럼값을 비교하는 부분만 그냥 행이 있나 없나만 비교하는것만 다를 뿐 전체적인 흐름은 동일합니다.


INSERT 트리거 역시 A에서 B호출, B에서 다시 A호출할때 A에서 트리거를 발생시킨 레코드가 COMMIT이 되지 않았다면 무한루프에 빠져야하는데

그러지 않고 제가 구상한 로직대로 잘 진행이 된다는 것 입니다..




여하튼 해결은 


위에서 말한 javaSp의 4-1) 단계로 진입하기전 현재 자신의 커넥션(jdbc:default)에서 방금 업데이트 된 레코드를 select하는 쿼리를 추가하였더니, 그 이후로는 무한루프에 빠지지 않습니다.


다시 말해 javasp에서 default커넥션이 무언가 동작을 해야 commit이 되는것을 확인했습니다.

 



제가 이번에 트리거를 처음 다뤄본것도 있고, 개발 경력이 아주 미비하여..

트랜잭션에 대한 개념이 확실하게 박혀있진 않습니다.


때문에 위에서 말한 상황들이 정상적인 결과라면 뭐.. 죄송합니다!!

  


다만 혹시나 하자가 있을 수 있는 부분이기에.. 해결방법을 공유드립니다.





항상 수고 많으시고, 다시 한번 친절한 답변 감사드립니다~!





Articles