트랜잭션은 데이터베이스의 논리적 연산단위이다.
흔히 계좌이체를 많이 설명하는데 이보다 더 적합한 사례는 찾아보기가 힘들다.
돈을 보내는 사람의 계좌에서 이체금액을 차감하고, 돈을 받는 사람의 계좌에 이체금액을 가산한다. 즉 계좌이체라는 업무는 이러한 2가지 단계로 진행되며, 데이터 정합성을 위해 위 작업은 전부 실행되든지 아니면 전부 취소되든지 해야 한다.
즉 하나의 업무 단위로 묶여서 처리돼야 한다는 것이고 이러한 업무 단위를 트랜잭션이라고 한다. 데이터 모델링 진행 시에도 트랜잭션을 표현할 수 있다.
고객이 상품을 구매하면서 발생하는 것이 주문이다. 또한 하나의 주문은 여러개의 상품을 구매할 수 있다. 이에 대한 모델이 위의 사진이다. 그렇다면 주문과 주문 상세의 데이터는 함께 발생되든지, 아니면 독립적으로 발생되는지를 생각해보아야한다.
위의 모델은 주문과 주문상세 모델의 관계가 선택적임을 표현하고 있다. 이는 주문에 대해 주문상세 데이터가 없을 수도 있다는 것이다.
대부분의 모델링 툴에서는 선택적 관계 표현이 기본 설정이다. 모델 작성자는 이를 꼭 인지하고, 습관적으로 관계의 선택사양을 간과하고 있는지 고려해봐야 한다.
일반적인 쇼핑몰 모델은 주문과 주문상세의 데이터가 태생적으로 동시에 발생된다면 당연히 계좌이체의 경우처럼 하나의 트랜잭션으로 묶어서 처리해야 한다.
All or Nothing인 원자성이 보장되도록 개발을 해야한다. 즉 커밋의 단위를 하나로 묶어야 함을 의미한다. 그래야만 트랜잭션은 전체가 실행되거나 혹은 전체가 취소될 수 있다.
// A -> B 계좌이체
Step1. 계좌이체API{잔고수정(고객번호 =>A, 수정값=>현재잔고-이체금액);
잔고수정(고객번호 =>B, 수정값=>현재잔고+이체금액);
commit();}
위의 의사코드는 A고객이 B고객에게 계좌이체하는 것을 표현한 것이다. 잔고 차감/가산 단게가 모두 성공해야지만 커밋이 수행되어 정상적인 데이터를 반영할 수 있다.
데이터 발생시 주문의 INSERT문과 주문상세의 INSERT문이 따로 개발되어서는 안된다. 만일 이를 따로 개발한다면 어떤 문제가 발생될 수 있을까
// 고객의 주문 발생
Step1. 주문API{주문입력(주문번호=>110001, 고객명=>A, ...);
commit();}
Step2. 주문상세API{주문상세입력(주문번호=>110001, 상품번호=>1234,...);
commit();
}
어차피 함께 수행되어야 하는 주문API와 주문상세API를 각각 호출해야 한다. 문제는 주문하는 도중에 핸드폰 배터리가 다 되었을수도 있고 앱을 실수로 꺼버렸을 수도 있으며 장애가 발생하여 연결이 끊어질 수도 있다. 이렇게 다양한 요인들로 인해 함께 수행되지 못하고 하나만 수행된다면 잘못된 데이터가 발생한다. 반드시 하나의 트랜잭션으로 처리 되어야 한다.
//고객의 주문 발생
Step1. 주문API{주문입력(주문번호=>110001, 고객명=>A, ...);
주문상세입력(주문번호=>110001, 상품번호=>1234,...);
commit();}
출처: SQL전문가가이드