Home Spring DB - 트랜잭션 이해
Post
Cancel

Spring DB - 트랜잭션 이해

트랜잭션

데이터를 데이터베이스에 저장하는 대표적인 이유는 데이터베이스가 트랜잭션 이라는 개념을 지원하기 때문

트랜잭션이란 데이터베이스에서 하나의 작업을 안전하게 처리하도록 보장해주는 것을 뜻함

예를 들면, A가 B에게 1000원 계좌이체를 한다고 생각했을떄,

  • A의 잔고 1000원 감소
  • B의 잔고 1000원 증가

위 두가지 작업이 합쳐 하나의 작업처럼 동작해야 함. 만약 첫번쨰 작업만 성공하고 두번쨰 작업이 실패한다면 A의 잔고만 1000원 감소하는 심각한 문제가 발생하게 돰. 이러한 문제에 대하여 데이터베이스의 트랜잭션은 첫번쨰, 두번째 작업이 둘다 함꼐 성공해야 데이터를 저장하고 중간에 하나라도 실패하면 작업 전의 상태로 되돌아 갈 수 있도록 함 모든 작업이 성공해서 데이터베이스에 정상 반영되는것은 Commit, 작업중 실패하여 이전 상태로 되돌아 가는것을 Rollback 이라고 함

트랜잭션 ACID

트랜잭션은 원자성(Atomicity), 일관성(Consistency), 격리성(Isolation), 지속성(Durability)를 보장해야 함

  • 원자성(Atomicity)
    • 트랜잭션 내에서 실행한 작업들은 마치 하나의 작업인 것 처럼 모두 성공하거나 모두 실패해야 함
  • 일관성(Consistency)
    • 모든 트랜잭션은 일관성 있는 데이터베이스 상태를 유지해야 함
    • 데이터베이스에서 정한 무결성 제약조건을 항상 만족해야 함
  • 격리성(Isolation)
    • 동시에 실행되는 트랜잭션들이 서로에게 영향을 미치지 않도록 격리되어야 함
    • 동시에 같은 데이터를 수정하지 못하도록 해야 함
    • 격리성은 동시성과 관련된 성능이슈로 인하여 트랜잭션의 격리 수준(Isolation Level)을 선탠할 수 있음
  • 지속성(Durability)
    • 트랜잭션을 성공적으로 끝내며 그 결과가 항상 기록되어야 함
    • 중간에 시스템에 문제가 생기더라도 데이터베이스 로그 등을 사용하여 성공한 트랜잭션 내용을 복구 할 수 있어야 함

트랜잭션 격리 수준

  • Read Uncommited(커밋되지 않은 읽기)
  • Read Commited(커밋된 읽기)
  • Repeatable Read(반복 가능한 읽기)
  • Serializable(직렬화 가능)

성능과 데이터의 무결성을 어느정도 타협하여 보통 Read Commited(커밋된 읽기), Repeatable Read(반복 가능한 읽기)을 사용함

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

Alt text

  • 사용자는 웹 어플리케이션 서버(WAS)나 데이터베이스 접근 툴과 같은 클라이언트를 사용하여 데이터베이스 서버에 접근할 수 있음
  • 클라이언트는 데이터베이스 서버에 연결을 요청하고 커넥션을 맺게 되고 이때 데이터베이스 서버 내부에는 세션이라는 것을 생성함
    • 앞으로 해당 커넥션을 통한 모든 요청은 이 세션을 통해서 실행하게 됨
    • 예를 들어 개발자가 클라이언트를 통해 SQL을 전달하면 현재 커넥션에 연결된 세션이 SQL을 실행함
  • 세션은 트랜잭션을 실행하고 커밋 또는 롤백을 통해 트랜잭션을 종료 함. 이후 새로운 트랜잭션을 다시 시작 할 수 있음
  • 사용자가 커넥션을 닫거나 관리자가 세션을 갈제로 종료하면 세션을 종료됨
  • 만약 커넥션 풀이 10개의 커넥션을 생성하면 세션도 10개가 만들어짐

트랜잭션의 자동 커밋과 수동 커밋

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
drop table member if exists cascade;
create table member (
    member_id varchar(10),
    money integer not null default 0,
    primary key (member_id)
);

-- 자동 커밋(기본값)
set autocommit true; -- 자동 커밋 모드 설정
insert into member(member_id, money) values ('data1',10000); -- 자동 커밋
insert into member(member_id, money) values ('data2',10000); -- 자동 커밋

-- 수동 커밋
set autocommit false; -- 수종 커밋 모드 설정
insert into member(member_id, money) values ('data3',10000); -- 수동 커밋
insert into member(member_id, money) values ('data4',10000); -- 수동 커밋

-- 트랜잭션 성공하여 커밋
commit;

-- 트랜잭션 실패하여 롤백
rollback;
  • 자동 커밋
    • 자동 커밋으로 설정이 되면 각각의 쿼리 실행 직후에 자동으로 커밋을 호출함.
    • 직접 커밋이라 롤백을 호출하지 않아 편리하지만 반대로 쿼리를 하나하나 실행할 떄마다 자동으로 커밋이 되기 떄문에 트랜잭션 기능을 제대로 사용할 수 없음
    • 보통 기본 설정값으로 자동 커밋으로 되어있음
  • 수동 커밋
    • 수동 커밋 모드로 설정하는 것을 트랜잭션을 시작한다고 표현
    • 쿼리를 실항한 이후에 커밋, 롤백을 호출해주어야 함

수동 커밋 모드나 자동 커밋 모드는 한번 설정하면 해당 세션에서는 계속 유지됨

DB 락

세션1이 트랜잭션을 시작하고 데이터를 수정하는 동안 아직 커밋을 수행하지 않았는데 세션2에서 동시에 같은 데이터를 수정하게 되면 데이터의 무결정이 보장되지 않아 여러 문제를 야기함. 바로 트랜잭션의 원자성이 깨져버리게 되는것.

이러한 문제를 방지하려면 세션이 트랜잭션을 시작하고 데이터를 수정하는 동안에는 커밋이나 롤백 전까지 다른 세션에서 해당 데이터를 수정 할 수 없도록 막아햐 함

Alt text

  • 세션1은 memberA의 금액을 500원으로 변경하려하고 세션2는 같은 memberA의 금액을 1000원으로 변경하여 함

Alt text

  • 세션1이 먼저 트랜잭션을 시작하여 해당 필드의 락을 획득함
  • 락을 소유하고 있으므로 해당 필드에 update SQL을 수행함

Alt text

  • 세션2는 트랜잭션을 수행하려하지만 해당 필드의 락을 획득하지 못하여 대기함
  • 무한정 대기하는 것은 아니며 대기시간을 넘어가면 락 타임아웃 오류 발생
    • 락 타임아웃 시간은 설정가능함

Alt text

  • 세션1이 커밋을 수행하여 트랜잭션이 완료되고 락을 반환함

Alt text

  • 세션2가 락을 획득

Alt text

  • 세션2가 락을 획득한 이후 update SQL을 수행

Alt text

  • 세션2가 커밋을 수행하여 트랜잭션이 완료되고 락을 반환함

조회시 DB 락

데이터베이스마다 다르지만 보통의 경우 일반적으로 조회는 락을 사용하지 않고 바로 데이터를 조회함 그러나 주요한 계산 및 정보 획득을 위해 데이터를 조회할 떄 “select for update” 구문을 사용하여 락을 획득해 다른 세션에서 해당 데이터를 수정하지 못하게 할 수 있음

1
2
3
set autocommit false;
select * from member where member_id='memberA' for update;
commit;
  • 조회하면서 선택한 필드의 락도 획득함
  • 조회할 시점에 락이 없다면 락을 획득할 때까지 대기

트랜잭션의 적용

Alt text

  • 트랜잭션은 비지니스 로직이 있는 서비스 계층에서 시작해야 함
    • 비지니스 로직이 잘못되면 해당 비지니스 로직으로 인한 문제가 되는 부분을 함께 롤백 해야하기 떄문
  • 트랜잭션을 시작하려면 커넥션이 필요하기 떄문에 서비스 계층에서 커넥션을 만들고 트랜잭션 커밋 이후 커넥션을 종료해야 함
  • 어플리케이션에서 DB 트랜잭션을 사용하려면 트랜잭션을 사용하는 동안 같은 커넥션을 유지해야 항상 같은 세션으로 사용할 수 있음
    • Alt text

주의

  • 트랜잭션과 락은 실제 동작하는 방식이 데이터베이스 마다 다르기 떄문에 사용하는 데이터베이스의 메뉴얼을 확일할 필요가 있음

참고

  • 스프링 DB - 데이터 접근 핵심 원리(김영한)
This post is licensed under CC BY 4.0 by the author.