CodeGym /행동 /SQL SELF /실제 시나리오에서 트랜잭션 사용 예시

실제 시나리오에서 트랜잭션 사용 예시

SQL SELF
레벨 39, 레슨 3
사용 가능

가끔 트랜잭션은 슈퍼히어로 영화에 나오는 캐릭터 같아. 장애나 에러, 문제 상황에서 우리 데이터베이스를 구해주거든. 여러 작업을 한 번에 처리해야 하고, 그 작업들이 따로따로 실행되면 안 될 때 트랜잭션이 한 번에 처리해줘. 결제 처리 예시로 어떻게 동작하는지 같이 살펴보자.

결제 처리

클래식한 상황을 상상해봐: 두 개의 은행 계좌가 있고, 한 계좌에서 다른 계좌로 돈을 보내고 싶어. 이건 그냥 "한 번에 끝"나는 작업이 아니야. 한 계좌에서 돈을 정확히 빼고, 다른 계좌에 제대로 더해야 해. 실수하면 큰일 나지: 둘 다 그대로거나, 밸런스가 꼬일 수도 있어(예를 들어 돈이 사라지거나 갑자기 생길 수도 있음).

시나리오: 계좌 간 돈 이체

이게 우리 코드야. 멀리 은하에서 온 메시지처럼 집중해서 읽어보자:

-- 트랜잭션 시작
BEGIN;

-- 1단계. 송금자 계좌에서 돈 빼기
UPDATE accounts
SET balance = balance - 100
WHERE account_id = 1;

-- 2단계. 수신자 계좌에 돈 더하기
UPDATE accounts
SET balance = balance + 100
WHERE account_id = 2;

-- 다 잘 됐으면 변경사항 저장!
COMMIT;

여기서 중요한 건 뭐야?

  • 1단계나 2단계에서 뭔가 잘못되면(예: 쿼리 에러, 잔액 부족 등), 트랜잭션은 롤백(ROLLBACK)으로 원래 상태로 돌릴 수 있어.
  • COMMIT은 모든 단계가 성공해야만 변경사항이 적용된다는 걸 보장해.

잔액 체크 추가하기

만약 송금자 잔액이 부족하면 어떡하지? 실수로 "마이너스"로 만들지 않게 잔액 체크를 추가해보자.

-- 트랜잭션 시작
BEGIN;

-- 송금자 현재 잔액 가져오기
DO $$
DECLARE
    current_balance NUMERIC;
BEGIN
    SELECT balance INTO current_balance FROM accounts WHERE account_id = 1;

    -- 돈이 충분한지 확인
    IF current_balance >= 100 THEN
        -- 충분하면 이체 실행
        UPDATE accounts
        SET balance = balance - 100
        WHERE account_id = 1;

        UPDATE accounts
        SET balance = balance + 100
        WHERE account_id = 2;

        -- 변경사항 저장
        COMMIT;
    ELSE
        -- 부족하면 롤백
        ROLLBACK;
        RAISE NOTICE '이체할 금액이 부족해!';
    END IF;
END $$;

여기서 더 흥미로운 점은?

  • PL/pgSQL 블록에서 IF로 조건 체크를 해. 잔액이 부족하면 트랜잭션이 거절되고 아무것도 안 바뀌어.
  • ROLLBACK은 변경사항이 있으면 취소해주고(여기선 아직 바뀐 게 없지만, 습관적으로 넣는 게 좋아).
중요!

이 강의는 트랜잭션의 실제 사용 시나리오에 관한 거라서, 실제 생활에서 쓸 수 있는 예시를 들었어. 여기엔 저장 프로시저도 들어가고, PL-SQL로 작성됐어. 이제 너희가 이 코드가 어떻게 동작하는지 이해할 만큼 충분히 경험이 쌓였다고 생각해. 나중에 PL-SQL 주제로 돌아와서 훨씬 더 복잡한 예제도 다뤄볼 거야.

트랜잭션으로 데이터 대량 업데이트

트랜잭션은 돈 이체 같은 작업뿐만 아니라 여러 상황에서 유용해. 예를 들어, 인터넷 쇼핑몰 데이터베이스에서 매일 수십 개의 주문이 "배송 중"에서 "완료"로 상태가 바뀔 수 있어. 여러 레코드를 한 번에 업데이트할 때, 혹시라도 장애가 나면 변경사항을 되돌릴 수 있어야 하지. 당연히 트랜잭션을 써야지.

또 다른 시나리오: 주문 상태 업데이트.

예시 코드:

-- 트랜잭션 시작
BEGIN;

-- 1단계. 배송일이 지난 주문 업데이트
UPDATE orders
SET status = '완료'
WHERE delivery_date < CURRENT_DATE;

-- 2단계. 성공적으로 업데이트됐다고 알림
RAISE NOTICE '모든 주문 상태가 성공적으로 업데이트됐어.';

-- 변경사항 적용
COMMIT;

뭔가 잘못되면?

항상 에러가 날 가능성은 있어. 예를 들어, WHERE 조건을 깜빡해서 모든 주문의 상태가 완료로 바뀌었을 수도 있지. 이런 상황을 막으려면 트랜잭션을 끝내거나 명시적으로 롤백하는 게 중요해.

롤백 시나리오 예시:

-- 트랜잭션 시작
BEGIN;

-- 1단계. 조건 없이 주문 업데이트 시도(앗, 실수!)
UPDATE orders
SET status = '완료';

-- 에러 때문에 트랜잭션 롤백
ROLLBACK;

-- 이제 주문은 그대로야

SAVEPOINT로 "유연성" 추가하기

항상 전체 트랜잭션을 롤백할 필요는 없어. 여러 단계로 이루어진 작업이라면, 일부만 롤백하고 싶을 수도 있지. 이럴 때 SAVEPOINT가 등장해.

이제 시나리오는 이렇게 돼: 여러 단계를 처리하면서, 그 중 한 단계만 롤백할 수 있게 하는 거야.

예를 들어, 주문 처리할 때 여러 단계가 있어: 창고에서 상품 빼기, 주문 상태 업데이트, 고객에게 알림 보내기. 만약 알림 보내기가 실패하면, 그 단계만 롤백하고 나머지 변경사항은 유지하고 싶을 수 있지.

-- 트랜잭션 시작
BEGIN;

-- 1단계. 창고에서 상품 빼기
UPDATE products
SET stock = stock - 1
WHERE product_id = 101;

-- 롤백 포인트 저장
SAVEPOINT step1;

-- 2단계. 주문 상태 업데이트
UPDATE orders
SET status = 'shipped'
WHERE order_id = 202;

-- 고객 알림 보내기 시도
SAVEPOINT step2;
-- 앗, 알림 과정에서 에러!
ROLLBACK TO SAVEPOINT step2;

-- 이제 트랜잭션을 안전하게 끝내기로 결정
COMMIT;

마무리

트랜잭션은 단순한 기술 도구가 아니라, 데이터의 무결성을 지켜주는 보증수표야. "도미노 효과"처럼 한 번의 실수로 전체 시스템이 무너지는 걸 막아주지. 여러 관련 작업을 할 때마다 스스로에게 물어봐: "이 중 하나라도 실패하면 어떻게 되지?" 만약 답이 "재앙"이라면, 트랜잭션을 쓸 때야. 기억해: 트랜잭션 코드 몇 분 더 쓰는 게, 장애 후 데이터 복구에 몇 시간 쓰는 것보다 훨씬 나아. 네 사용자(그리고 네 멘탈)가 고마워할 거야!

2
과제
SQL SELF, 레벨 39, 레슨 3
잠금
주문 상태 일괄 업데이트
주문 상태 일괄 업데이트
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION