DB 트랜잭션

MinSeong Kang·2022년 5월 3일
0

IT 지식

목록 보기
5/11

데이터베이스 트랜잭션?

  • 데이터베이스의 상태를 변환시키는 하나의 논리적 기능을 수행하기 위한 작업의 단위 또는 일련의 연산들을 의미한다.
  • 데이터베이스를 통한 하나의 거래를 안전하게 처리하도록 보장한다.

트랜잭션의 성질

트랜잭션이 성공적으로 처리되어 데이터베이스의 무결성과 일관성을 보장하기 위해서는 4가지 특성을 만족해야한다. (트랜잭션 ACID)

  • Atomicity (원자성)
    트랜잭션 내에서 실행한 작업들은 마치 하나의 작업인 것처럼 모두 성공하거나 모두 실패해야한다.
  • Consistency (일관성)
    모든 트랜잭션은 일관성 있는 데이터베이스 상태를 유지해야 한다.
    시스템이 가지고 있는 조건 요소는 트랜잭션 수행 전과 트랜잭션 수행 완료 후의 상태가 같아야 한다.
  • Isolation (격리성)
    동시에 실행되는 둘 이상의 트랜잭션이 서로에게 영향을 미치지 않도록 격리한다. 수행중인 트랜잭션이 완료될 때까지 다른 트랜잭션의 연산이 끼어들 수 없다.
  • Durablility (지속성)
    트랜잭션을 성공적으로 완료하면 그 결과는 항상 기록되어, 중간에 시스템에 문제가 발생하더라도 데이터베이스 로그 등을 사용해서 성공한 트랜잭션 내용을 복구해야 한다.

트랜잭션 연산

데이터 변경 쿼리를 실행하고 데이터베이스에 그 결과를 반영하려면 commit을, 반영하고 싶지 않으면 rollback을 호출한다. 이 때 commit을 호출하기 전까지는 임시로 데이터를 저장하는 것이기 때문에 다른 세션는 변경 데이터를 볼 수 없다.
1) 자동 커밋 : 자동 커밋으로 설정하면 각 쿼리는 실행 직후 자동으로 commit이 호출되어 결과가 반영된다. 따라서 commit이나 rollback을 따로 호출하지 않아도 되는 편리함이 있지만, 쿼리가 실행 직후 결과가 반영되기 때문에 트랜잭션 기능은 제대로 사용할 수 없다.

set autocommit true;

2) 수동 커밋 : 수동 커밋으로 설정하면 쿼리 실행 이후 꼭 commit이나 rollback을 호출해주어야 한다. 따라서 수동 커밋을 설정하는 것은 트랜잭션을 시작한다고 표현한다.

set autocommit false;

트랜잭션 예시

회원A와 회원B에게 각각 10000원씩 있다고 가정해보자. 회원A가 회원B에게 3000원을 계좌이체하는 상황이라면, 다음과 같은 쿼리를 작성할 수 있다.

update member set money=10000-4000 where member_id = "memberA";
update member set money=10000+4000 where member_id = "memberB";

위 예시 쿼리에는 오류가 없기 때문에 자동 커밋이든 수동 커밋이든 특별한 문제 없이 실행시킬 수 있다.

update member set money=10000-4000 where member_id = "memberA";
update member set money=10000+4000 where memberrr_id = "memberB";

위 예시에서 두번째 쿼리는 문제가 있다. 따라서 자동 커밋으로 설정되어 있는 상태에서 두 쿼리를 실행시킨다면, 회원A의 돈은 4000원이 빠져나간 상태이지만, 두번째 쿼리는 실행되지 않아 회원B의 돈은 그대로 10000원일 것이다. 이런 문제를 방지하기 위해서 수동 커밋 설정으로 트랜잭션을 수행해야 하며, 트랜잭션 도중 문제가 발생하면 rollback을 호출하여 트랜잭션 시작 전 단계로 데이터를 복구해야한다.

DB 락

트랜잭션을 시작하여 데이터를 수정하는 도중에 다른 트랜잭션이 동시에 같은 데이터를 수정하려고 하면 문제가 발생한다. 이 문제를 방지하기 위해, DB 락은 어느 세션이 트랜잭션을 시작하고 데이터를 수정하는 동안에는 커밋이나 롤백하기 전까지 다른 세션은 해당 데이터를 수정할 수 없고, 대기하게 한다.

  • 대기한 세션은 무기한 대기할 수 없기 때문에 락 타임 아웃 시간을 설정할 수 있다. 타임 아웃 시간동안 락을 얻지 못하면 타임아웃 오류가 발생한다.
SET LOCK_TIMEOUT 60000 // 60초
  • 일반적으로 변경 쿼리가 아닌 조회 쿼리(SELECT)를 할때는 락을 하지 않고 바로 조회 가능하다. 만약 조회 시점에 락이 필요하다면 select for update를 사용하면 된다. 이를 통해 다른 세션은 해당 데이터를 접근할 수 없으며, 해당 트랜잭션이 종료할 때까지 대기해야 한다.
select * from member where memeber_id = 'memberA' for update;

참고 자료

https://www.inflearn.com/course/스프링-db-1/dashboard
https://coding-factory.tistory.com/226

0개의 댓글