트랜잭션 예제

박준형·2025년 3월 25일

데이터베이스

목록 보기
5/6

📌 데이터베이스 연결 구조와 세션

사용자가 애플리케이션 서버나 데이터베이스 접근 툴을 사용해서 데이터베이스 서버에 연결 요청을 하고 커넥션을 맺게 된다. 이때 데이터베이스 서버는 내부에 세션 을 만든다.
커넥션과 세션은 1:1 로 매핑되는듯 하다.

✅ 과정

  • 개발자가 클라이언트(애플리케이션 서버, 데이터베이스 접근 툴)를 통해 SQL을 전달하면 커넥션이 연결된 세션이 SQL 실행
  • 세션은 트랜잭션을 시작하고 commit or rollback 을 통해 트랜잭션을 종료하면 이후에 새로운 트랜잭션을 다시 시작 가능
  • 사용자가 커넥션을 닫거나 DBA(데이터베이스 관리자)가 세션을 강제로 종료하면 세션은 종료

📌 예제로 이해하기

트랜잭션에 관한 예제들은 READ COMMITED(커밋된 읽기) 트랜잭션 격리 수준으로 설정되어 있는 상황입니다.

  • 데이터 변경 쿼리를 실행하고 데이터베이스에 결과를 반영하려면 commit 을 호출하고, 반영하고 싶지 않다면 rollback 을 호출
  • commit 호출 전까지는 임시로 데이터를 저장하여 해당 트랜잭션을 시작한 세션에게만 변경 데이터가 보이고 다른 세션은 볼 수 없음 -> 만약 READ UNCOMMITED(커밋되지 않은 읽기) 가 트랜잭션 격리 수준으로 설정되어 있다면 볼 수 있다.

1️⃣ 신규 데이터 추가 - commit 전

  1. 세션1 이 트랜잭션을 시작하고 신규 회원1, 신규 회원2를 데이터베이스에 추가(아직 커밋하지 않음)
  2. 새로운 데이터는 임시 상태로 저장되어 세션1 만 조회 가능
  3. 세션2select 쿼리를 실행해도 임시 상태의 신규 데이터 조회 불가능
//트랜잭션 시작
set autocommit false; //수동 커밋 모드
insert into member(member_id, money) values ('newId1',10000);
insert into member(member_id, money) values ('newId2',10000);

왼쪽이 세션1 오른쪽이 세션2 이다. 실제 h2 데이터베이스에서 확인한 결과 commit 실행을 하지 않아 세션1 에서만 조회가 가능하고 세션2 에서는 조회할 수 없다.

⚠️ 만약 커밋하지 않은 데이터를 다른 세션에서 조회할 수 있다면?

위 상황을 예로 들자면 세션2 가 신규 데이터 조회가 가능하여 조회한 후 해당 데이터로 어떠한 로직을 수행할 수 있다. 이때 세션1rollback 을 수행한다면 신규 데이터는 데이터베이스에 반영되지 않아 데이터 정합성에 문제가 발생한다. 즉, commit 전의 데이터를 조회할 수 있다면 rollback 이 실행됐을 때 문제가 발생하므로 commit 전의 데이터는 다른 세션에서 보이지 않아야 한다.

2️⃣ 신규 데이터 추가 - commit 후

  1. 세션1 이 신규 데이터를 추가하고 commit 호출
  2. 새로운 데이터가 실제 데이터베이스에 반영되고, 데이터의 상태가 임시 -> 완료 로 변경
  3. commit 이 완료됐으므로 세션2 에서도 신규 데이터 조회 가능
// 커밋 실행
commit;

commit 을 호출하면 신규 데이터가 데이터베이스에 반영되어 세션2 에서도 조회가 가능한 것을 볼 수 있다.

3️⃣ 신규 데이터 추가 - rollback

  1. 세션1 에서 신규 데이터를 추가한 다음 rollback 을 호출
  2. 세션1 이 데이터베이스에 반영한 모든 데이터가 처음 상태로 원상 복구
    3.! 수정 또는 삭제를 수행한 데이터도 rollback 이 호출되면 트랜잭션 시작 직전의 상태로 복구
//트랜잭션 시작
set autocommit false; //수동 커밋 모드
insert into member(member_id, money) values ('newId1',10000);
insert into member(member_id, money) values ('newId2',10000);

위 SQL을 실행하면 세션1 에서는 신규 데이터 조회가 가능하다.

// 롤백 실행
rollback;

하지만 rollback 을 호출하게 되면 데이터베이스에 반영이 되지 않는다.


📌 계좌이체 상황

현재 데이터베이스에는 memberA 10000원 memberB 10000원의 데이터가 들어있다.

1️⃣ 계좌이체 정상 - commit

set autocommit false;
update member set money=10000 - 2000 where member_id = 'memberA';
update member set money=10000 + 2000 where member_id = 'memberB';

memberAmemberB 에게 2000원을 이체하는 상황이다.

commit 호출 전이므로 memberA 에게는 변경된 데이터가 보이지만 memberB 는 원래 데이터가 조회된다.

commit;

이때 commit 을 호출하게 되면 memberB 의 세션에서도 memberA 의 잔액이 8000원으로 감소, memberB 의 잔액이 12000원으로 증가한 것을 볼 수 있다.

2️⃣ 계좌이체 문제 발생 - commit

set autocommit false;
update member set money=10000 - 2000 where member_id = 'memberA'; //성공
update member set money=10000 + 2000 where member_iddd = 'memberB'; //예외

해당 쿼리를 실행하면 컬럼을 찾을 수 없다는 오류로 memberA 의 잔액은 2000원 감소하지만, memberB 의 잔액은 증가하지 못하고 유지된다.

commit;

이 상태에서 commit 을 호출하면 memberA 의 잔액만 줄어드는 심각한 문제가 발생한다. 즉, 이러한 문제가 발생한다면 commit 을 호출하면 안된다. rollback 을 호출하여 데이터를 트랜잭션 시작 시점으로 원상 복구해야 한다.

3️⃣ 계좌이체 문제 발생 - rollback

위에서 발생한 예외 상황에서 이번에는 rollback 을 호출해보겠다.

rollback;

rollback 을 호출하면 계좌이체 실행하기 전 상태 즉, 데이터가 트랜잭션 시작 시점으로 원상 복구 되는 것을 확인할 수 있다.

✅ 정리

  • 원자성
    트랙잭션 내에서 실행하는 작업들은 마치 하나의 작업처럼 모두 성공 모두 실패 해야 한다. 트랜잭션의 원자성 덕분에 여러 SQL 명령어를 마치 하나의 작업처럼 처리할 수 있다.

  • 자동 커밋
    데이터베이스는 기본 설정이 자동 커밋이기 때문에 하나의 쿼리가 완료되면 commit 이 호출된다. 수동 커밋 모드를 사용해야 중간에 실패해도 rollback 을 호출하여 원상 복구 시킬 수 있다. 자동 커밋에서 수동 커밋으로 전환 하는 것을 트랜잭션을 시작한다고 표현한다.

profile
으쌰 으쌰

0개의 댓글