데이터에 변경이 생겼을 때 즉, DB에 insert, update, delete가 발생했을 때 자동적으로 실행되는 프로시저
사용자의 닉네임 변경 이력을 저장하는 트리거
delimiter $$
CREATE TRIGGER log_user_nickname_trigger
BEFORE UPDATE -- update 이전에 트리거 발생
ON users FOR EACH ROW -- users 테이블에서 이벤트가 발생하면 트리거 발생, update 된 row에 대해 트리거 실행
BEGIN
insert into users_log values(OLD.id, OLD.nickname, now());
END
$$
delimiter ;
select * from users;
select * from users_log;
update users set nickname = 'taetae' where id = 1;
✔️ OLD란❓
update 되기 전의 tuple, delete된 tuple
사용자가 마트에서 상품을 구매할 때마다 지금까지 누적된 구매 비용을 구하는 트리거
delimiter $$
CRAETE TRIGGER sum_buy_prices_trigger
AFTER INSERT -- buy 테이블에 insert가 발생한 후에 insert가 발생한 row에 대해 트리거 발생
ON buy FOR EACH ROW
BEGIN
DECLARE total INT;
DECLARE user_id INT DEFAULT NEW.user_id;
select sum(price) into total from buy where user_id = user_id;
update user_buy_stats set price_sum = total where user_id = user_id;
END
$$
delimiter ;
select * from buy;
select * from user_buy_stats;
insert into buy (user_id, price, buy_at) values (1, 5000, now());
✔️ NEW란❓
insert된 tuple, update된 후의 tuple
update, insert, delete 등을 한번에 감지하도록 설정 가능(MySQL은 불가능)
-- postgresql
CREATE TRIGGER avg_empl_salary_trigger
AFTER INSERT OR UPDATE OR DELETE
ON employee
FOR EACH ROW
EXECUTE FUNCTION update_avg_empl_salary();
UPDATE employee SET salary = 1.5 * salary WHERE dept_id = 1003;
✔️위 update문을 실행하면,
1003 부서에 임직원이 다섯명이 있다면 FOR EACH ROW로 트리거를 실행했기 때문에 avg_empl_salary_trigger는 다섯 번 실행된다.
row 단위가 아니라 statement 단위로 trigger가 실행될 수 있도록 할 수 있다.(MySQL은 FOR EACH STATEMENT 사용 불가능)
-- postgresql
CREATE TRIGGER avg_empl_salary_trigger
AFTER INSERT OR UPDATE OR DELETE
ON employee
FOR EACH STATEMENT
EXECUTE FUNCTION update_avg_empl_salary();
UPDATE employee SET salary = 1.5 * salary WHERE dept_id = 1003;
✔️위 update 문을 실행하면,
1003 부서에 임직원이 다섯 명이 있어도 FOR EACH STATEMENT에 의해 avg_empl_salary_trigger는 한 번만 실행된다.
trigger를 발생시킬 디테일한 조건을 지정할 수 있다 (MySQL은 불가능)
-- postgresql
CREATE TRIGGER log_user_nickname_trigger
BEFORE UPDATE
ON users
FOR EACH ROW
WHEN (NEW.nickname IS DISTINCT FROM OLD.nickname)
EXECUTE FUNCTION log_user_nickname();
J가 H에게 20만원 이체한 것을 transaction으로 구현
START TRANSACTION; -- transaction 시작
UPDATE account SET balance = balance - 200000 WHERE id = 'J';
UPDATE account SET balance = balance + 200000 WHERE id = 'H';
COMMIT; -- transaction 종료
✔️COMMIT 이란❓
J가 H에게 30만원 이체한 것을 transaction으로 구현
START TRANSACTION;
UPDATE account SET balance = balance - 300000 WHERE id = 'J';
select * from account;
ROLLBACK;
✔️ROLLBACK 이란❓
각각의 SQL문을 자동으로 transaction 처리 해주는 개념
SQL문이 성공적으로 실행하면 자동으로 commit 한다.
실행 중에 문제가 있었다면 알아서 rollback한다.
MySQL에서는 default로 autocommit이 enabled되어 있다.
예제
SELECT @@AUTOCOMMIT;
insert into account values ('W', 1000000);
✔️autocommit이 enabled된 상태이기 때문에
insert문을 실행하면 자동으로 commit이 되면서 account 테이블에 ('W', 1000000) 데이터가 영구적으로 저장된다.
select * from account;
SET autocommit = 0; -- autocommit 비활성화
DELETE FROM account WHERE balance <= 1000000;
ROLLBACK;
✔️autocommit을 off 한 후에 delete 했기 때문에 rollback을 한다면 다시 이전 상태로 돌아갈 수 있다.
START TRANSACTION;
UPDATE account SET balance = balance - 200000 WHRER id = 'J';
UPDATE account SET balance = balance + 200000 WHERE id = 'H';
COMMIT;
✔️ START TRANSACTION 실행과 동시에 autocommit은 off 된다.
✔️ COMMIT / ROLLBACK과 함께 transaction이 종료되면 원래 autocommit 상태로 돌아간다.
Atomicity
Consistency
Isolation