[Trigger 에러 노트] Can't update table 'Board' in stored function/trigger because it is already used by statement which invoked this stored function/trigger

beans·2022년 11월 30일
0

1 발생 원인

테이블에 DML이 들어오면 교착 상태 방지를 위해 잠금이 수행되고, 잠금되어있는 동안에는 다른 DML이 수행될 수 없다. 결국 동일 테이블(A 테이블에서 A 테이블)로 트리거를 발생 시키는 것은 불가능.

1.1 문제의 trigger 코드

CREATE DEFINER=`cube`@`%` TRIGGER on_comment_insert
AFTER INSERT
ON Board FOR EACH ROW
BEGIN
    IF NEW.isComment = 1 THEN
				UPDATE Board SET Board.commentCnt = Board.commentCnt + 1
				WHERE Board.idx = NEW.parentIdx ;

        -- CALL update_board_commentCnt(NEW.parentIdx, 1);
	END IF;
END

1.2 의문점

근데 AFTER INSERT인데 그럼 DML이 종료된 이후에 실행되어야 맞는 것 아닌가?

⇒ 트리거는 쿼리문이 완전히 실행되기 전에 실행된다. 그 증거로 바뀌기 이전의 데이터와 바뀔 데이터를 가져올 수 있는 old.필드명, new.필드명이 있다. 쿼리문이 완전히 종료되는 COMMIT 또는 ROLLBACK이 일어나기 전까지 테이블은 데이터 무결성을 위해 LOCK 상태이기 때문에 동일 테이블을 Trigger로 수정할 수 없다.

2 해결 방안

2.1 댓글 테이블을 별도로 생성한 후 트리거 사용

  • 채택 여부

댓글 테이블에 insert가 일어날 경우 board 테이블의 어느 게시판에 해당하는 댓글인지 검사한 후 클라이언트로부터 전달받은 parentIdx와 일치하는 레코드의 commentCnt를 더하거나 빼준다.

2.2 트리거를 사용하지 않고 쿼리문으로 수행

  • 채택 여부

트리거는 머리 속 DB 설계가 지속적으로 남아있지 않다면 많이 사용할 수록 유지보수가 어렵게 되고, 재귀 또는 반복문이 많을 경우 큰 성능 저하를 야기할 수 있다.

그렇기 때문에 이 부분은 아예 트리거를 사용하지 않고 쿼리를 요청할 때 commentCnt 값을 더하거나 뺀 값으로 쿼리를 요청하면 된다.

3 참조

  1. https://www.phpschool.com/gnuboard4/bbs/board.php?bo_table=qna_db&wr_id=167686
  2. https://stackoverflow.com/questions/15300673/mysql-error-cant-update-table-in-stored-function-trigger-because-it-is-already
  3. https://okky.kr/articles/911268
  4. https://title-developer.tistory.com/146
  5. https://jaeone94.github.io/posts/Postgresql-트리거를-배워보자/

0개의 댓글