1. 트랜잭션이란?
단일 쿼리로는 해결할 수 없는 로직을 처리할 때 보통 트랜잭션을 사용하게 됩니다. 최근 스프링부트에서 @Transactional 애너테이션을 사용하여 수정로직을 구성하였습니다. 이처럼 하나의 쿼리로 해결할 수 없는 로직을 처리해야 할 때 사용하는 개념은 트랜잭션에 대해서 알아보겠습니다.
트랜잭션이란 DB의 상태를 변경시키거나 하나의 논리적 기능을 수행하기 위한 일종의 작업의 단위라고 할 수 있습니다.
쉽게 말해 한꺼번에 수행되어야 할 연산을 모아놓은것이라 할 수 있습니다.
트랜잭션으로 묶인 연산들은 모두 처리되거나 아니면 하나도 처리하지 않거나 둘 중 하나 입니다.
4개중 2개 처리 같이 작업의 일부만 적용되는 현상은 트랜잭션에서 발생하지 않습니다.
위와 같이 모두 처리되거나 하나도 실행하지 않은 트랜잭션에 특징은 작업의 완전성을 보장해줍니다.
예를 들어보겠습니다. 쇼핑몰에서 운동화를 산다고 할때 이때 수행되는 작업은 2개 입니다.
1. 결제 완료하기
2. 재고에서 상품배송하기
이 두가지는 항상 함께 이루어져야 합니다. 하지만 시스템에 오류가 발생한다면 돈이 결제 되었는데 상품이 배송이 안되거나 결제가 실패하였는데 운동화가 빠져나가는 경우가 생길 수 있습니다.
이런 상황을 방지하기 위해 트랜잭션이란 걸 이용하게 됩니다.
결제가 성공하면 돈이 빠져 나가고 창고에서도 운동화가 차감돼서 배송이 되어야 합니다.
도중에 오류가 발생하면 결제도 취소되고 상품도 원래로 돌아가야 합니다.
즉 중간에 작업이 실패해도 아무일도 없었던 원래 상태로 돌아가게 됩니다.
이처럼 완전한 작업을 완성하기 위해 트랜잭션은 총 4가지의 특징을 가지고 있습니다. 각 특징은 트랜잭션이 안전하고 신뢰할 수 있는 데이터처리를 보장하기 위해서 반드시 필요한 요소들입니다. 그럼 각 특징에 대해 알려드리겠습니다.
2. 트랜잭션의 특징(ACID)
트랜잭션의 특징은 크게 4가지로 구분됩니다.
1. 원자성(Atomicity)
원자성이란 트랜잭션이 모두 실행되거나, 전혀 실행되지 않아야 한다는 개념입니다. 진행중인 트랜잭션에 오류가 발생하면 모든 작업이 원래 상태로 롤백되어야 합니다. 예를 들어 은행에서 A가 B에게 송금했는데 송금 과정에서 한쪽계좌에서 돈이 빠져나갔지만 다른 계좌에 입금되지 않으면 큰 문제가 발생하게 됩니다. 이러한 상황을 방지하기 위해 원자성이 필요합니다.
2. 일관성(Consistency)
트랜잭션이 실행되기 전과 후에의 데이터 상태는 항상 일관성을 유지해야 합니다. 예를 들어보겠습니다. A가 B에게 송금을 해도 A와 B의 계좌 잔액의 총합은 변하지 않아야 합니다.
3. 고립성(Isolation)
고립성이란 여러 트랜잭션이 동시에 실행될 때 서로 영향을 미치지 않도록 보장하는 것입니다. 만약 트랜잭션 A가 실행되는 도중에 트랜잭션B가 같은 데이터를 수정한다면 트랜잭션 결과에 오류가 발생 할 수 있습니다. 이를 방지하기 위해 데이터베이스는 트랜잭션이 독립적으로 수행되도록 관리합니다.
4. 지속성(Durability)
지속성이란 트랜잭션이 성공적으로 완료된 후에도 시스템 오류가 발생하더라도 그 결과가 영구적으로 저장된다는 것을 의미합니다. 즉 트랜잭션이 완료된 후에는 데이터를 잃어버릴 걱정 없이 안전하게 보관 할 수 있어야 합니다. 보통 트랜잭션이 장성적으로 완료(commit)된 경우에는 버퍼의 내용을 하드디스크(데이터베이스)에 확실히 기록해야 하고 부분완료 된 경우에는 작업을 취소해야 합니다. 정상적으로 완료 혹은 부분 완료된 데이터는 DBMS가 책임지고 데이터베이스에 기록하는 성질이 지속성이며 영속성이라고 표현하기도 합니다.

3. 스프링부트에서의 트랜잭션
스프링에서는 @Transactional 어노테이션을 붙이기만 하면 Spring이 자동으로 트랜젝션을 관리해 줍니다. 이것을 선언적 트랜잭션이라고 합니다. 트랜잭션을 처리하는 방식에는 선언적 방식과 명시적(프로그래밍적) 방식이 있습니다. 명시적 트랜잭션은 TransactionTelpate또는 PlatformTransactionManager을 직접 사용하여 좀 더 세밀하게 트랜잭션을 처리하는 방법입니다. 스프링에서는 @Transactional 애너테이션만으로도 간단하게 트랜잭션을 사용할 수 있습니다.
예를 들어보겠습니다.
위에서 예시를 들었던 상품의 결제처리와 재고 상품 전송 기능이 있습니다. 이 둘을 트랜잭션으로 묶어 처리하겠습니다.
@Service
@RequiredArgsConstructor
public class OrderService {
private final PaymentService paymentService;
private final InventoryService inventoryService;
@Transactional // 선언적 트랜잭션 처리
public void placeOrder(Long userId, Long productId) {
// 1. 결제 처리
paymentService.processPayment(userId, productId);
// 2. 재고 감소 처리
inventoryService.decreaseStock(productId);
}
@Transactional이 적용시켜 placeOrder() 메서드는 전체가 하나의 트랜잭션으로 실행합니다.
결제 처리와 재고 감소가 모두 정상적으로 이루어지면 DB에 반영됩니다. 하지만 중간에 오류가 발생하면 이전에 수행된 작업도 롤백됩니다.
4. 트랜잭션의 상태

트랜잭션은 실행 과정에서 여러 상태를 거칩니다. 트랜잭션의 대표적인 상태는 다음과 같습니다.
1. 활성(Active)
트랜잭션이 시작되었고 연산이 수행되는 상태입니다. 아직 커밋되지 않았기 때문에 데이터베이스에 확정 반영되지 않은 상태입니다.
2. 부분완료(Partially Committed)
트랜잭션의 모든 연산이 실행되었지만 아직 커밋되지 않은 상태입니다. 이 상태에서 시스탬 장애가 발생하면 롤백이 됩니다.
3. 실패(Failed)
트랜잭션 실행 도중 오류가 발생하여 정상적으로 완료되지 못한 상태입니다. 롤백이 필요한 상태라 할 수 있습니다.
이 상태에서는 커밋할 수 없으며, 반드시 롤백해야 합니다.
4. 완료(Committed)
트랜잭션이 성공적으로 실행되었으며 모든 변경사항이 데이터베이스에 확정 반영된 상태 입니다.
이제 변경된 데이터는 영구적으로 저장이 됩니다.
커밋된 이후에는 롤백이 불가능하며 데이터가 영구적으로 저장되었기 때문에 장애가 발생해도 데이터가 유지가 됩니다.
5.철회(Aborted)
트랜잭션이 실패하여 변경사항을 모두 취소하고 원래 상태로 복구한 상태입니다.
이전 상태로 되돌려야 할 때 사용됩니다.
5. 병행제어(Concurrency Control)
병행제어란 여러 트랜잭션이 동시에 실행될 때 데이터의 일관성과 무결성을 유지하는 기법입니다. 병행제어를 통해 트랜잭션간의 충돌을 방지하고 동시에 트랜잭션을 처리 할 수 있습니다.
병행제어가 없다면 데이터손상이 발생할 수 있고 트랜잭션 간 충돌로 인해 잘못된 데이터가 저장될수도 있습니다. 예를 들어 여러 사용자가 동시에 데이터를 수정하거나 한 사용자가 데이터를 읽는 도중 다른 사용자가 데이터를 변경하면 동시에 실행되는 트랜잭션 간에 충돌이 발생합니다.
병행 실행 시 발생하는 문제점
- 갱신 손실
여러 트랜잭션이 같은 데이터를 수정할 때 한 트랜잭션의 변경사항이 덮어씌어지는 문제입니다.
두개의 트랜잭션이 한 개의 데이터를 동시에 갱신 할 때 발생합니다.
예를 들어보겠습니다. 트랜잭션 A와 트랜잭션 B가 있습니다. 트랜잭션A는 상품에 재고에 +10을 하는 트랜잭션이고 트랜잭션 B는 상품에 -10을 하는 트랜잭션입니다. 기존 재고가 20개라고 가정하겠습니다. 먼저 A를 실행시킵니다. 그리고 A가 커밋되지 않은 상태에서 B를 실행시킵니다. 그럼 A가 커밋된 후에는 재고가 30개가 됩니다. 하지만 B는 A가 커밋되지 않은 시점에서 실행 시켰기 때문에 A가 커밋된 이후의 30개의 재고가 아닌 기존에 20개의 재고에서 -10을 하는 연산을 실행시키게 됩니다. 그렇게 되면 재고는 10개가 됩니다. 이상태에서 B를 커밋하게 되면 A와 B가 서로 정상적으로 실행시켰을 때의 결과값은 20이 아니라 B가 커밋한 결과가 A의 커밋한 결과를 덮어써버리는 문제가 발생하여서 재고가 10개가 되게 됩니다.
기존방식: 기존재고:20 → A실행 → 재고:30 → B실행 → 재고20
갱신손실 발생 시: 기존재고:20 → A실행 20+10 → A의 결과가 반영(커밋)되기전에 B실행 20-10 → A 커밋(재고:20) →B커밋(재고:10) → A의 데이터를 B가 덮어씌어 A의 데이터 손실 결과값으로 B의 커밋결과만 반영 - 모순성
여러 트랜잭션이 동시에 실행될 때 한 트랜잭션이 일부 데이터는 변경되기 전의 값을 읽고 다른 데이터는 변경된 후의 값을 읽어서 데이터가 불일치 하는 상태가 되는 것 입니다. 결과적으로 같은 시점에서 조회했어야 할 데이터가 서로 맞지 않는 문제가 발생합니다.
예를 들어보겠습니다. 초기 데이터에는 A계좌에 1500원 B계좌에는 1000원이 있습니다.
수행할 트랜잭션으로는 T1과 T2가 있습니다. T1은 A계좌에 +300원 B계좌에 +300원을 증가시킵니다.
T2는 A계좌를 3배증가시키고 B계좌를 3배 증가시킵니다.
첫번째로 T1에서 A계좌를 읽습니다(A:1500원) T1에서 A계좌에 300원을 추가하고 저장합니다(A:1800) 하지만 아직 트랜잭션이 완료되지 않은 상태에서 T2가 시작됩니다. A와 B가 3배 증가합니다.(A:5400,B:3000) 트랜잭션 T1이 B계좌를 읽습니다.(B:3000+300) 하지만 T1에서 B계좌를 읽으려고 하니까 T2가 3배 증가시켜서 변경된 값을 읽게 됩니다. 결국 T1트랜잭션에서 A는 T2의 영향을 받기 전인 변경 전 값을 읽었지만 B는 T2의 영향을 받은 변경 후 값을 읽었기 때문에 둘의 데이터가 한 트랜잭션 내에서 서로 다른 기준으로 처리가 됩니다. 이렇게 모순성이 발생하게 됩니다. - 연쇄 복귀
하나의 트랜잭션이 실패하여 롤백(Rollback)될 떄 해당 데이터를 사용한 다른 트랜잭션도 영향을 받아 롤백해야 하는 문제 입니다.
트랜잭션 A가 데이터를 변경하고 커밋 전에 트랜잭션 B가 이를 읽어서 사용을 합니다. 그런데 트랜잭션 A가 롤백(Rollback) 되면 트랜잭션 B가 읽은 데이터는 잘못된 데이터가 되어버립니다. B도 롤백해야 하는 상황이 발생하여 연쇄적으로 롤백이 전파됩니다.
예를 들어보겠습니다. 계좌A에 1500원이 있고 계좌 B에 1000원이 있습니다. 트랜잭션 T1은 계좌 A에서 300원을 증가 시키고 계좌 B에서는 200원이 감소됩니다. 트랜잭션 T2는 A계좌의 잔액을 3배 증가 시킵니다.
트랜잭션 T1이 실행됩니다. A계좌의 잔액이 1800원으로 증가됩니다. 그리고 아직 T1이 커밋되기 이전에 T2가 A계좌의 변경된 값을 읽은 후 A의 계좌가 3배 증가되어 5400원으로 변경 된 후 커밋이 됩니다.
트랜잭션 T1이 실패하여 롤백을 해야합니다. A계좌의 값을 다시 1500원으로 되돌리려고 합니다. 하지만 T2는 이미 A계좌를 5400으로 변경을 완료하고 커밋한 상태입니다.
A게좌는 원래 1500원이 있는데 롤백으로 인해 되돌려야 하지만 T2가 이미 5400원으로 변경 완료 되어 T2의 트랜잭션을 롤백할 수 없는 상태가 되어버리는 문제가 발생하게 됩니다. - 더티 리드
트랜잭션 A가 아직 커밋하지 않은 데이터를 트랜잭션 B가 읽을 경우 나중에 트랜잭션 A가 롤백하면 B가 읽은 데이터는 잘못된 데이터가 됩니다.
트랜잭션 B는 뮤효된 데이터를 읽게되어 잘못된 결과를 도출하게 됩니다. - 반복 불가능한 읽기
같은 데이터를 두번 읽었을 때 값이 변경되는 경우 발생하게 됩니다.
트랜잭션이 같은 데이터를 여러번 읽었을 때 다른 트랜잭션이 데이터를 변경하면 일관성이 깨지게 됩니다.
예를 들어 계좌의 잔액이 1000이고 트랜잭션 A가 있고 트랜잭션 B가 있습니다. 트랜잭션 A가 계좌의 잔액을 읽습니다.(잔액:1000) 그 뒤 트랜잭션 B에서 계좌의 잔액을 +1000하고 커밋을 하게 됩니다.(잔액:2000) 그리고 트랜잭션 A가 다시 잔액을 읽게 됩니다.(결과2000) 같은 데이터를 두번 읽었지만 값이 달라지게 됩니다. - 유령데이터 읽기
첫번째 조회 후 같은 조건으로 조회했는데 결과가 달라지는 문제 입니다.
다른 트랜잭션이 새로운 데이터를 삽입하거나 삭제하면 발생하게 됩니다.
예를 들어 기존 주문목록에 신발이 있습니다. 트랜잭션 A에서 주문목록을 조회합니다. 그럼 결과값으로 신발이 나오게 됩니다. 그 뒤 트랜잭션 B에서 주문목록에 양말을 추가한 뒤 커밋을 하게 됩니다. 이후 트랜잭션에서 다시한번 주문목록을 조회하게 됩니다. 그러면 결과값으로 신발과 양말이 나오게 됩니다.
같은 조건으로 조회했지만 이전에 없던 데이터가 읽히게 되면서 결과가 달라지게 됩니다.
위와 같이 병행실행 시 발생하는 문제점들을 해결하기 위해 병행제어를 이용 할 수 있습니다.
트랜잭션이 동일한 데이터 항목에 대해 임의적인 병행 접근을 하지 못하도록 로킹기법을 사용하여 하나의 데이터에 접근하는 트랜잭션들을 제어 할 수 있습니다.
락킹(Locking)
트랜잭션이 데이터에 접근할 때 다른 트랜잭션이 동시에 변경하거나 읽지 못하도록 잠금을 거는 기법입니다.
데이터 무결성과 일관성을 유지하면서도 병행실행을 조절하는데 중요한 역할을 합니다.
락킹 기법은 비관적 락(Pessimistic Lock)과 낙관적 락(Optimistic Lock)으로 나눌 수 있습니다.
1. 비관적 락
트랜잭션이 데이터를 사용하는 동안 다른 트랜잭션이 해당 데이터에 접근하지 못하도록 차단하는 방식입니다.
비관적 락은 공유락과 베타락으로 나뉠 수 있습니다. 트랜잭션이 읽기를 할 때는 공유락을 사용하게 되고 읽고 쓰기를 할 때는 베타락을 사용하게 됩니다. 트랜잭션 T가 데이터 항목A에 대해서 공유락을 설정 할 경우 트랜잭션 T는 해당 데이터 항목에 대해서 읽을 수 는 있지만 기록 할 수는 없습니다. 그리고 Read는 서로 영향을 주지 않기 때문에 다른 트랜잭션도 공유락을 동시에 설정 할 수 있습니다. 트랜잭선 T가 데이터 항목 B에 대해서 베타락을 설정 할 경우 트랜잭션 T는 B에 대해서 읽을 수도 있고 기록 할 수도 있습니다. Write는 영향을 주는 작업이므로 다른 트랜잭션은 베타락을 설정한 데이터 항목 B에 대해서 어떠한 lock도 설정 할 수 없습니다.
공유락과 베타락을 사용하는 규칙
- 데이터에 락이 걸려 있지 않으면 트랜잭션은 데이터에 락을 걸 수 있습니다.
- 트랜잭션이 데이터 X를 읽기만 할 경우 LS(X)를 요청하고, 읽거나 쓸 경우 LX(X)를 요청합니다.
- 다른 트랜잭션이 데이터에 LS(X)를 걸어둔 경우, LS(X)의요청은 허용하고 LX(X)는 허용하지 않습니다.
- 다른 트랜잭션이 데이터에 LX(X)를 걸어둔 경우, LS(X)와 LX(X) 모두 허용하지 않습니다.
- 트랜잭션이 락을 허용받지 못하면 대기 상태가 됩니다.
2. 낙관적 락
트랜잭션이 데이털르 변경할 때까지 잠금을 걸지 않고 최종적으로 변경을 시도 할 때 충돌을 감지하는 방식입니다.
낮은 충돌 가능성을 전제로 하며 성능을 극대화하는 동시에 데이터 일관성을 유지하는 기법입니다. 충돌이 발생하면 트랜잭션을 롤백시키고 다시 시도하게 만듭니다.
비관적락을 이용하면 트랜잭션이 길어질수록 잠금 유지 시간이 길어져 성능이 저하가 되고 동시 처리 성능이 떨어지게 됩니다. 또한 불필요한 대기 시간이 많아 질 수 있습니다. 그에 비해 낙관적 락은 잠금을 사용하지 않기 때문에 불필요한 대기시간이 없고 높은 동시성을 지원합니다. 충돌이 적을 경우 성능이 매우 우수합니다. 하지만 트랜잭션의 충돌이 많을 경우 재시도가 발생히기 때문에 오히려 성능이 저하 될 수 있습니다.
동시성이 높은 환경이거나 충돌이 적고 성능이 중요하며 읽기가 많고 쓰기가 적은 경우 낙관적 락을 사용하는게 더 적합합니다.
반대로 충돌이 빈번하게 발생하거나 중요한 데이터를 다루며 안정성이 중요한 경우 비관적 락을 사용하게 됩니다.
데드락(Deadlock)
데드락이란 두개 이상의 트랜잭션이 서로 상대방의 자원이 해제되기를 기다리면서 영원히 진행되지 않는 상태 입니다.
데드락은 교착상태라고도 합니다.
예를들어 T1에서 A에 대해 락을 걸고 T2에서는 B에 대해 락을 걸었다고 가정하겠습니다. 그리고 나서 T1에 B에 대해 락을 걸고 T2가 A에 대해 락을 걸면 T1과 T2는 서로 A,B에 대한 락을 유지하며 무한루프에 빠지게 됩니다. 일반적으로 데드락이 발생하면 DBMS가 T1혹은 T2 하나를 강제로 중지시켜 한 트랜잭션은 정상적으로 실행시키고 중지된 트랜잭션은 원래 상태로 되돌려 놓습니다.
6. 트랜잭션 고립 수준
DBMS는 트랜잭션을 동시에 실행시키면서 락보다 좀 더 완화된 방법으로 문제를 해결하기 위해 트랜잭션 고립 수준 명령어(Transaction Isolation Level Instruction)라는 걸 이용하게 됩니다.
트랜잭션 고립 수준 명령어는 총 4가지로 이루어져 있습니다.
1.READ UNCOMMITTED(Level 0)
가장 낮은 고립수준으로 트랜잭션에 공유락을 걸지 않고 배타락을 사용한 상태 입니다.
공유락을 걸지 않았기 때문에 다른 트랜잭션이 아직 커밋하지 않은 데이터를 읽어 올 수 있습니다.
반복불가능한 읽기와 유령읽기, 더티리드가 발생할 수 있습니다.
베타락을 사용하기 때문에 갱신 손실 문제를 방지 할 수 있습니다.
데이터의 정확성과 일관성이 중요한 경우 사용하지 않습니다.
2. READ COMMITTED(Level 1)
SQL Server와 Oracle의 기본값으로 사용되는 고립수준입니다.
트랜잭션이 데이터를 읽을 때 공유락을 걸지만 트랜잭션이 끝나기 전이라도 데이터 읽기가 끝나면 락을 바로 해제합니다.커밋한 데이터만 읽을 수 있으며 SELECT문이 실행되는 동안만 공유락이 유지됩니다.
이로 인해 더티리드는 방지되지만 반복불가능한 읽기와 유령읽기는 여전히 발생 할 수 있습니다.
3. REPEATABLE READ(Level 2)
트랜잭션이 데이터를 읽으면 해당 데이터에 대한 공유락을 트랜잭션이 종료될 때까지 유지합니다.
트랜잭션이 완료 되 때까지 SELECT문이 사용하는 모든 데이터에 공유락이 걸립니다.
다른 트랜잭션은 해당 데이터에 대해 수정 할 수 없지만 새로운 데이터의 삽입은 가능합니다.
더티리드와 반복불가능한 읽기는 방지합니다.
그러나 유령읽기는 여전히 발생할 수 있습니다.
4. SERIALIZABLE(Level 3)
가장 높은 고립 수준으로 트랜잭션을 완벽하게 격리시킵니다.
트랜잭션이 SELECT 문으로 읽는 데이터 뿐만 아니라 해당 범위 전체에 공유락이 걸립니다.
다른 트랜잭션은 해당 범위에 UPDATE 및 INSERT도 불가능 합니다.
트랜잭션이 읽는 데이터뿐만 아니라 해당 범위 전체에 대해 락을 걸어 더티리드, 반복불가능한 읽기, 유령읽기를 모두 방지 합니다.
데이터의 정확성과 일관성이 가장 높지만 동시성이 가장 낮아 성능에 영향을 줄 수 있습니다.
| 트랜잭션 고립수준 | Dirty Read 방지 | 반복불가능한 읽기 방지 | 유령읽기 방지 | 동시성 수준 |
| READ UNCOMMITTED | ✖ 불가능 | ✖ 불가능 | ✖ 불가능 | 매우 높음 |
| READ COMMITTED | ✔ 가능 | ✖ 불가능 | ✖ 불가능 | 높음 |
| REPEATABLE READ | ✔ 가능 | ✔ 가능 | ✖ 불가능 | 보통 |
| SERIALIZABLE | ✔ 가능 | ✔ 가능 | ✔ 가능 | 낮음 |
7. 회복
DB에 장애가 발생했을 때 DB를 일관성 있는 상태로 되돌리는 DBMS의 기능입니다.
데이터베이스를 갱신하는 과정에서 장애가 발생한 경우 회복절차를 수행하여 장애 발생 이전의 데이터베이스로 만드는 것을 회복이라고 합니다. 회복하기 위해서는 데이터의 복사본을 이용합니다. 회복할 때 데이터의 복사본에 적힌 내용을 사용해서 복원을 하게 됩니다. 데이터의 복사본을 만드는 방법에는 덤프(Dump)와 로그(Log)를 이용하는 방법 2가지가 있습니다. 덤프는 가장 기본적인 기법으로 일정 주기로 원본의 데이터베이스의 모든 내용을 다른 저장장치에 복사하는 것입니다.
로그는 변경 이전의 데이터베이스를 기준으로 변경 연산이 발생 할 때 마다 로그 파일을 작성하여 기록하고 회복할 때 로그에 적힌 내용을 사용하여 복원하는 방법입니다.
로그
트랜잭션이 수행중이거나 종료 후 발 생하는 손실을 방지하기 위해 DB기록을 추적하는 로그파일을 사용합니다.
트랜잭션이 반영한 모든 DB 변경사항을 DB에 기록하기 전에 미리 기록해두는 별도의 DB로 안전한 하드디스크에 저장되며 기록이남습니다.
장애가 발생하여 시스탬 재가동시 DBMS는 로그파일을 먼저 살펴봅니다.
DBMS는 트랜잭션이 종료되었는지 혹은 중단되었는지 여부를 판단합니다.
종료된 트랜잭션은 종료를 확정하기 위해 재실행(REDO)를 진행하고 중단된 트랜잭션은 없던일로 되돌리기 위해 취소(UNDO)를 진행합니다.
REDO(재실행)
REDO는 트랜잭션이 커밋된 작업을 데이터베이스에 다시 적용하여 작업이 영속성을 유지하도록 보장 합니다.
데이터를 DB에 기록하기 전에 로그가 디슼크에 먼저 기록되고 데이터는 캐시에 머물다가 나중에 디스크로 기록됩니다. 하지만 시스템이 갑자기 장애가 발생하여 커밋된 트랜잭션의 데이터가 디스크에 쓰여지지 않았을 수도 있습니다. 이때 REDO작업을 통해 해당 트랜잭션의 작업을 다시 수행하여 디스크의 데이터를 일관된 상태로 복원합니다.
시스템이 장애로 인해 커밋된 트랜잭션의 데이터가 기록되지 못했을 때 로그에 기록된 수정후의 값을 사용하여 데이터를 복구합니다.
UNDO(되돌리기)
UNDO는 커밋되지 않은 트랜잭션의 작업을 원래 상태로 되돌리는 작업으로 원자성을 보장합니다.
트랜잭션이 작업을 수행하던 중 장애가 발생하면 일부 데이터만 변경된 상태로 남아 데이터 불일치가 발생할 수 있습니다.그래서 시스템 장애가 발생하면 커밋되지 않은 트랜잭션의 로그를 사용하여 작업을 취소합니다. 커밋되지 않은 트랜잭션의 변경사항은 모두 취소되어야 하므로 UNDO 작업을 통해 변경 전의 상태로 복원해야 합니다.
UNDO작업은 수정 전의 값을 사용하여 데이터의 원래 상태로 복구합니다.
'개발자 취업준비 > springboot' 카테고리의 다른 글
| 스프링 시큐리티 실전 적용하기1 스프링시큐리티 설정 (0) | 2025.03.25 |
|---|---|
| 스프링시큐리티 (0) | 2025.03.11 |
| 스프링프로젝트3 글 삭제 및 수정 (0) | 2025.02.17 |
| 스프링부트 프로젝트2 글 목록 조회하기 (1) | 2025.02.16 |
| 스프링부트 프로젝트1 계층구조를 구성하여 글 저장 로직 작성하기 (0) | 2025.02.16 |