Til
title: 2025-11-07 author: 강병호 date: 2025-11-07 category: TIL/강병호/2025/11 (파일 경로 : TIL/{이름}/{연}/{월}) layout: post (자유) —
읽기에는 트랜잭션을 걸지 않아도 될까요?
-
대답
읽기에는 상황에 따라 트랜잭션의 필요 유무가 달라집니다. 트랜잭션을 걸지 않아도 되는 경우는 주로 데이터가 약간 변경되도 상관없는 즉, 일관성을 맞추기 위한 오버헤드보다 성능이 중요한 경우 트랜잭션을 이용하지 않습니다. 예를 들어, 대시보드, 로그 확인, 댓글 등과 같은 상황에서 이러한 부분에서 트랜잭션을 걸지 않아도 됩니다. 유튜브 댓글같은 경우에도 일관성이 보장되지 않는 경우가 있는데 상대적으로 일관성이 중요하지 않기 때문에 이렇게 처리될 수 있습니다.
다만, 일관성, 정확성이 중요한 읽기 작업 또한 존재합니다. 주로, 읽은 데이터가 이후 로직에 영향을 주게 되는 경우에 이를 사용합니다. 예를 들어, 송금을 하게 되는 경우를 고려해보자. 송금1 트랜잭션, 송금 2 트랜잭션에서 잔액을 조회하고 송금할 때, 두 트랜잭션 모두 50000원이라는 잔액을 조회한다. 그 후 각자 50000원을 다른 계좌로 송금한다고 했을 때, 이미 송금1 트랜잭션에서 50000원을 보냈다면 송금2 트랜잭션에서는 이 과정이 실행될 수 없다. 하지만 이미 송금2 트랜잭션의 읽기 과정에서 50000원을 조회했기에 일관성을 유지하지 못하게 되는 경우가 발생한다. 이러한 경우 읽기에도 트랜잭션이 적용되어야 한다.
트랜잭션은 기본적으로 데이터의 일관성을 보장하는 단위 작업이다. 이는 쓰기에서만 데이터를 보호하는 것이 아닌 읽기 과정에서도 일관된 상태를 보장할 필요가 있기에 읽기에서도 트랜잭션을 걸 필요가 있다.
트랜잭션을 걸지 않아도 되는 경우
- 데이터가 약간 변경되도 상관 없는 경우
- 일관성보다 성능이 더 중요한 시스템
- 대시보드, 로그 확인, 댓글
트랜잭션을 걸어야하는 경우
일관성이나 정확성이 중요한 경우로 주로 읽은 데이터가 이후 로직에 영향을 주는 경우이다.
-
읽은 데이터로 쓰기 하는 경어
조회한 데이터를 기반으로 쓰기 작업을 수행하는 경우에는 트랜잭션이 필요하다.
SELECT stock FROM product WHERE id=1; -- 5 UPDATE product SET stock = stock - 1 WHERE id=1;- 위 트랜잭션이 수행되는 순간에 SELECT는 이미 5를 가져왔지만 다른 트랜잭션에서 재고를 변경해 3이 된 경우 일관성이 깨졌다고 볼 수 있다.
이러한 문제를 해결하기 위해서 우리는 트랜잭션으로 묶어서 데이터를 처리해야한다.
BEGIN; SELECT stock FROM product WHERE id=1 FOR UPDATE; UPDATE product SET stock = stock - 1 WHERE id=1; COMMIT;FOR UPDATE: row-level에 Exclusive Lock을 걸어 다른 트랜잭션이 같은 행을 수정하지 못하게 처리한다.- 격리 수준 : 최소 READ COMMITED 이상을 이용한다.
-
여러 읽기 쿼리에서 결과가 달라지는 경우
하나의 트랜잭션 내에서 시점이 일관되지 않게 된다.
# Tx1 SELECT SUM(balance) FROM account; -- 총액 1000 SELECT COUNT(*) FROM account; -- 중간에 Tx2 완료 # Tx2 INSERT 11 INTO account;- 두 SELECT 는 다른 시점의 스냅샷을 읽음
- 결과가 일치하지 않는다
- 주로 이러한 것은 보고서, 통계 검증 과정에서 불일치하게 되는 경우로 이러한 상황은 문제가 된다.