스프링을 사용하면서 @Transactional 이라는 어노테이션을 적용해본 적이 있습니다.
메서드 위에 해당 어노테이션을 적용하면 메서드 안에 있는 쿼리들이 하나의 단위로 묶인다는 대략적인 용도만 고 있습니다. 그래서 @Transactional 어노테이션의 정확한 개념을 모르고 사용했기 때문에 의문점이 많이 들었습니다.
트랜잭션이란?
트랜잭션을 사용해야 하는 상황은?
스프링에서는 트랜잭션을 어떻게 지원하는지?
1️⃣ 트랜잭션이란?
더이상 나눌 수 없는 가장 작은 하나의 단위를 의미
데이터베이스에서는 트랜잭션을 조작함으로써 사용자가 데이터베이스에 대한 완전성을 신뢰할 수 있도록 함
모든 데이터베이스는 자체적으로 트랜잭션을 지원
하나의 명령을 실행했을 때 데이터베이스가 온전히 그 명령을 실행해주는 것 => 성공하면 커밋(Commit) => 실패하면 롤백(Rollback)
데이터베이스는 기본적으로 트랜잭션을 관리하기 위한 설정을 갖고 있습니다.
명령을 끝마칠 때까지 수행 내역을 로그에 저장해둡니다. - 데이터베이스에 반영된 내용을 재반영하기 위한 redo log - 수행을 실패해 이전의 상태로 되돌리는 undo log * 두 개의 log를 이용해 트랜잭션을 지원합니다.
2️⃣ 트랜잭션을 사용하는 상황(예시)과 성질
트랜잭션에서 가장 흔히 볼 수 있는 입출금을 예시로 들어보겠습니다.
A가 B에게 만원을 송금하려고 합니다.
A의 계좌에 만원보다 많은 금액이 있는지 확인합니다.
A의 계좌에 만원보다 많은 금액이 있다면 만원을 차감합니다.
차감한 만원의 금액을 B의 계좌에 더해줍니다.
위 업무는 순서를 나눠놨지만 절대로 분리되거나 일부만 실행되면 안 되는 하나의 작업입니다.
이렇게 절대로 깨져서는 안되는 하나의 작업을 트랜잭션이라고 합니다.
트랜잭션의 네가지 성질
원자성(Atomicity) - A가 B에게 송금을 하는데 A의 계좌에서 만원이 차감만 되고 작업이 종료되면 문제가 발생합니다. - 이렇듯 일부만 실행되는 경우는 없다는 원자성을 지닙니다. - [롤백]1번부터 4번까지 연결된 하나의 작업에서 어느 하나의 명령이라도 실패하면 롤백을 하게 됩니다. - [트랜잭션 커밋]반대로 1번부터 4번까지 작업이 성공적으로 수행하면 수정된 내용 데이터베이스에 반영 - 롤백이나 커밋이 실행되어야 트랜잭션이 종료됩니다.
일관성(Consistency) - 데이터베이스 내의 상태 혹은 계층 관계 - 컬럼의 속성이 항상 일관되게 유지되어야 함 - 컬럼의 속성이 수정되었다면 trigger를 통해 일괄적으로 모든 데이터베이스에 적용해야 합니다.
지속성(Durability) - 트랜잭션이 성공적으로 수행되어 커밋되었다면 어떠한 문제가 발생하더라도 데이터베이스에 그 내용이 영원히 지속되어야한다는 지속성이 있습니다. - 이를 위해 모든 트랜잭션은 로그로 남겨져 어떠한 장애에도 대비할 수 있도록 합니다.
독립성(Isolation) - 트랜잭션 수행 시 다른 트랜잭션이 끼어들 수 없고 각각 독립적으로 실행된다는 성질 DB 독립성의 문제점(더보기 클릭)
하지만 데이터베이스에 작업이 들어왔을 때 모든 작업의 독립성을 보장해 하나씩 순차적으로 진행하게 된다면, CPU는 DBMS보다 인풋, 아웃풋이 빈번히 수행되기 때문에 트랜잭션을 순차적으로 시행하면 CPU는 점점 응답을 기다리는 시간이 길어지게 됩니다. 그 결과 프로그램이 비효율적으로 동작하는 문제가 발생합니다.
이처럼 데이터베이스에 저장된 데이터의 무결성과 동시성의 성능을 지키기 위해 트랜잭션의 설정이 중요한 것입니다.
여러 명령을 하나의 트랜잭션으로 묶고 싶은 경우 개발자가 직접 트랜잭션의 경계설정을 통해 트랜잭션 명시