19. [SQL기초] 트리거로 자동처리하기
트리거는 테이블 행에 특정 이벤트가 발생하면 미리 작성해 둔 루틴, 또는 쿼리문이 실행되도록 하는 이벤트 기반 실행 로직입니다. 데이터베이스마다 구현 방식에 약간씩 차이는 있지만, 자동화된 연쇄 작업을 실행할 수 있도록 하는 편리한 기능입니다.
트리거를 작성할 때는 어떤 이벤트에 대해서 트리거를 작성할지를 먼저 고려해야 합니다.
트리거가 꼭 필요하지 않거나 무거운 데이터베이스 처리 작업을 트리거로 실행하면 데이터베이스에 불필요한 부하를 주게 되고, 데이터베이스가 느려지는 원인이 됩니다.
트리거를 잘 사용하면 전체 서비스의 부하를 경감시키고, 단순한 구조의 서비스를 구축할 수 있습니다.
쇼핑몰에서 이용자가 장바구니의 상품을 결제하면 주문 정보를 저장하고, 주문 메일을 발송하고, SMS 알림을 보내고, 재고 테이블의 재고를 줄여야 합니다. 그리고 이런 일련의 과정이 모두 완료되면 주문 완료 페이지를 이용자에게 표시해야 합니다.
주문 완료 처리 과정의 복잡함과 시간 지연을 줄이기 위해 SMS 발송과 이메일 발송은 주문 완료 페이지 표시 후에 발송되도록 해당 테이블에 일단 내용을 저장하기로 합니다. 이용자에게는 결제 페이지가 표시되기 직전의 모래시계로 보이지만 실제 주문을 완료하는 과정은 웹서버와 데이터베이스의 여러 단계에 거친 상호 작용을 통해 이루어집니다.
웹서버에서 쿼리문을 전송해 데이터베이스에 주문 정보를 저장하면 제어가 다시 웹서버로 돌아옵니다. 주문 정보 저장이 성공했으면 SMS 발송 테이블에 발송할 내용을 저장하고, 다시 실행 로직이 웹서버로 다시 돌아옵니다. 순차적으로 메일 발송할 내용도 테이블에 저장하고, 최종적으로 테이블이 기록할 내용이 모두 완료되면, 장바구니(basket) 테이블에서 주문 완료된 상품을 장바구니 목록에서 삭제하고 결제 모듈에 주문 성공 표시를 해서 최종적으로 결제 완료를 합니다.
그리고 이용자에게는 주문 완료 페이지를 호출합니다. 실제로는 여러가지 복잡한 주문 처리과정이 웹서버와 데이터베이스 사이에서 일어납니다.
여기서부터 중요합니다. 주문 완료를 하는 과정에서 웹서버는 여러 번의 데이터베이스 쿼리문 호출하게 되고, 실행 제어 로직을 주고받는 여러 과정을 거칩니다. 이 과정을 짧게 줄일 수 있으면 주문 완료처리가 훨씬 간결하고 빠르게 실행될 것입니다. 이때 트리거가 빛을 발합니다.
주문 정보 테이블에 행 추가 이벤트가 발생하면 추가된 주문 정보를 기초로 SMS 및 이메일 발송 테이블에 내용을 추가하고 장바구니를 비우는 트리거를 만들면 주문 정보 저장만으로도 데이터베이스에 저장할 모든 테이블 내용이 추가됩니다. 더 이상 웹서버가 실행 로직을 주고받을 필요도 없고, 주문 정보 저장 중간에 에러가 발행하면서 주문 정보에 문제가 생기는 것도 어느 정도는 방지할 수 있습니다.
이렇게 하면 웹서버는 주문정보만 저장한 후 즉시 주문 완료 페이지를 표시할 수 있게 됩니다. 나머지 추가 테이블에 저장하는 과정은 데이터베이스 안에서 한 번에 처리되기 때문에 웹서버와 상호 작용을 할 필요도 없고, 실행 시간도 대폭 단축됩니다.
트리거 등록
트리거는 “CREATE TRIGGER” 명령어로 코드 블록을 생성해서 등록합니다. 주문정보 테이블에 새 주문 행이 등록되면 SMS 발송 테이블에 SMS 발송 문을 등록하는 트리거를 작성해 보겠습니다.
먼저 트리거 기본 구조를 만듭니다. 앞뒤에 딜리미터 변환을 붙이고 트리거 블록을 선언합니다. 트리거 이름은 “tr_after_insert_sms”입니다. 스토어드 프로시저 이름 규칙처럼 접두어로 “tr_”을 붙여서 트리거임을 표시합니다.
delimiter $$
create trigger tr_after_insert_Sms
begin
end$$
delimiter ;
트리거가 언제 실행되는지 조건문을 추가합니다. 트리거 코드 블록 위에 다음 조건문을 추가합니다. “begin” 위에 빈 줄을 만들고 추가하면 됩니다. 주문정보 테이블(p_order)에 새로운 행(for each row)이 추가된(insert) 뒤에(after) 트리거 블록을 실행한다는 뜻입니다.
after insert on p_order for each row
트리거 코드 블록 안에 새로운 SMS 발송 문을 등록하는 쿼리문을 추가합니다.
insert into sms (mobile, content) values (NEW.mobile, '주문이 접수되었습니다.');
여기서 중요한 키워드가 하나 나옵니다. “NEW”는 새로 추가된 주문정보(p_order) 테이블의 새 주문행을 가리킵니다. “NEW.mobile”은 주문정보의 휴대폰 번호를 가져옵니다.
완성된 트리거는 다음과 같습니다. 트리거 코드를 실행해 트리거를 등록하면 이후 새로운 주문정보가 등록될 때마다 SMS 발송 테이블에 새로운 발송 정보가 자동으로 등록됩니다.
delimiter $$
create trigger tr_after_insert_Sms
after insert
on p_order for each row
begin
insert into sms (mobile, content) values (NEW.mobile, '주문이 접수되었습니다.');
end$$
delimiter ;