DataBase(MySQL)

트랜잭션(Transaction)이란? + Spring transactional

woo0doo 2023. 5. 1. 21:10

트랜잭션

 

 데이터베이스의 상태를 변화시키는 하나의 논리적 기능을 수행하기 위한 작업의 단위 또는 한꺼번에 수행되어야할 일련의 연산을 의미한다.

 여기서 데이터베이스의 상태를 변화시킨다의 의미는 질의어(SQL:SELECT, INSERT, DELETE, UPDATE)를 이용하여 데이터베이스에 접근하는 것을 의미한다.

 

 트랜잭션은 작업의 완전성을 보장해준다. 즉, 논리적인 작업 셋을 모두 완벽하게 처리하거나 또는 처리하지 못할 경우에는 원 상태로 복구해서 작업의 일부만 적용되는 현상이 발생하지 않게 만들어주는 기능이다.

 

은행에서 돈을 이체하는 작업을 예시로 들자면

 

1. A은행에서 B은행으로 돈을 계좌 이체하려고 함

2. 송금 중 알 수 없는 오류로 A은행에서 돈은 빠져나갔지만 B은행의 계좌에는 입금되지 않는 경우... 실제로 이런 현상이 발생하면 끔찍하다.


트랜잭션 상태

 

  • Active: 트랜잭션이 실행중인 상태(SQL 실행)
  • Parital Commit : 트랜잭션의 마지막 연산까지 실행했지만, commit 연산이 실행되기 직전의 상태
  • Commited : 트랜잭션이 성공적으로 종료되고 commit 연산까지 실행 완료된 상태
  • Failed : 트랜잭션 실행에 오류가 발생한 상태
  • Aborted: 트랜잭션이 비정상적으로 종료되어 Rollback 연산을 수행한 상태

1. Commit: 데이터베이스 내의 연산이 성공적으로 종료되어 연산에 의한 수정 내용을 지속적으로 유지하지 위한 명령어이다.

2. Rollback: 데이터베이스 내의 연산이 비정상적으로 종료되거나 정상적으로 수행이 되었다 하더라도 수행되기 이전의 상태로 되돌리기 위해 연산 내용을 취소할 때 사용하는 명령어이다.


트랜잭션 성질(ACID)

- Atomicity(원자성)

  • 트랜잭션이 데이터베이스에 모두 반영되던지, 아니면 전혀 반영되지 않아야 한다.
  • 트랜잭션 내의 모든 명령은 반드시 완벽히 수행되어야 하며, 모두가 완벽히 수행되지 않고 어느 하나라도 오류가 발생하면 트랜잭션 전부가 취소되어야 한다.

- Consistency(일관성)

  • 트랜잭션의 작업 처리 결과가 항상 일관성이 있어야 한다.
  • 시스템이 가지고 있는 고정요소는 트랜잭션 수행 전과 수행 완료 후의 상태가 같아야 한다.

 

Isolation(독립성)

  • 둘 이상의 트랜잭션이 동시에 실행되고 있을 경우 어떤 하나의 트랜잭션이라도 다른 트랜잭션의 연산에 끼어 들 수 없다.
  • 수행 중인 트랜잭션은 완전히 완료될 때까지 다른 트랜잭션에서 수행 결과를 참조 할 수 없다.

- Durability(지속성)

  • 트랜잭션이 성공적으로 완료되었을 경우, 결과는 영구적으로 반영되어야 한다.

트랜잭션을 하지 않으면 발생할 수 있는 문제들

- Dirty Read Problem

한 트랜잭션 진행 중에 변경한 값을 다른 트랜잭션에서 읽을 때 발생한다. 커밋되지 않은 상태의 트랜잭션을 다른 트랜잭션에서 읽을 수 있을 때 발생하는 문제이다.

- Non-repeatable Read Problem

한 트랜잭션에서 같은 값을 두 번 이상 읽었을 때 그 값이 다른 경우를 말한다. 한 트랜잭션 도중 다른 트랜잭션이 커밋되면 발생할 수 있는 문제이다.

 

- Phantom Read Problem

한 트랜잭션에서 같은 쿼리문을 두 번 이상 실행했을 때 새로운 데이터가 조회되는 경우를 말한다. A 트랜잭션 도중 B 트랜잭션에서 update 쿼리를 수행하고 커밋하더라도 A 트랜잭션에서 그 결과를 볼 수 없지만, A 트랜잭션 도중 B 트랜잭션에서 insert 쿼리를 수행할 경우 A 트랜잭션에서 처음에 안보였던 새로운 데이터가 조회될 수 있다.

 

 


Spring @Trasactional 어노테이션

 

스프링에서 @Transactional은 클래스나 메서드에 붙여줄 경우, 해당 범위 내 메서드가 트랜잭션이 되도록 보장해준다. 선언적 트랜잭션이라고도 하는데, 직접 객체를 만들 필요 없이 선언만으로도 관리를 용이하게 해주기 때문이다.

 

@Transational이 클래스 혹은 메서드에 붙을 때, Spring은 해당 메서드에 대한 프록시를 만든다. 프록시 패턴은 디자인 패턴 중 하나로, 어떤 코드를 감싸면서 추가적인 연산을 수행하도록 강제하는 방법이다.

 

트랜잭션의 경우, 트랜잭션의 시작과 연산 종류시의 커밋 과정이 필요하므로, 프록시를 생성해 해당 메서드의 앞뒤에 트랜잭션의 시작과 끝을 추가하는 것이다.

 

또한, 스프링 컨테이너는 트랜잭션 범위의 영속성 컨텍스트 전략을 기본으로 사용한다.

서비스 클래스에서 @Transaction을 사용할 경우, 해당 코드 내의 메서드를 호출할 때 영속성 컨텍스트가 생긴다는 뜻이다. 영속성 컨텍스트는 트랜잭션 AOP가 트랜잭션을 시작할 때 생겨나고, 메서드가 종료되어 AOP가 트랜잭션을 커밋할 경우 영속성 컨텍스트가 flush되면서 해당 내용이 반영된다. 이후 영속성 컨텍스트 역시 종료되는 것이다.

이러한 방식으로 영속성 컨텍스트를 관리해 주기 때문에, @Transaction을 쓸 경우 트랜잭션의 원칙을 정확히 지킬 수 있다.

 

더보기

추가적으로 유의하면 좋은 점들을 정리해놓은 블로그가 있기에 주소를 가져와봤다.

https://mommoo.tistory.com/92


참고: 

https://github.com/Seogeurim/CS-study/blob/main/contents/database/README.md#%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98(transaction)%EA%B3%BC-%EA%B5%90%EC%B0%A9%EC%83%81%ED%83%9C 

https://cocoon1787.tistory.com/808

https://code-lab1.tistory.com/51

https://kafcamus.tistory.com/30