Spring + DB

Transaction, Auto Commit, Rollback, Lock

cwchoiit 2023. 11. 30. 16:08
728x90
반응형
SMALL

DB를 사용할 땐 반드시 이해하고 있어야 하는 키워드인 '트랜잭션'은 이것 저것 다양한 내용이 참 많은듯하다.

 

우선 트랜잭션이란 DB에 어떤 작업을 하기 위해선 이 트랜잭션이 살아있는 주기동안에 일어나야한다. 즉, SELECT, UPDATE, INSERT 등 모든 DB에 대한 행위는 트랜잭션이 필요하고 이 트랜잭션이라는 단위가 시작되는 순간부터 종료되는 시점 사이에 대한 내용을 적어보자한다. 

 

728x90
반응형
SMALL

Auto Commit

오토 커밋은 트랜잭션이 종료될 때 자동으로 커밋을 수행하는 것을 말한다. 커밋은 DB에 어떤 행위를 수행한 후 그 행위를 DB에 적용하는 것을 말하는데 이 커밋을 수행하지 않으면 변경사항이 DB에 적용되지 않는다. 그리고 그 변경사항에 대한 적용을 자동으로 해주는 것이 오토 커밋이다. 

 

참고로 오토 커밋은 기본값이 오토 커밋인데, 이 오토 커밋을 꺼야하는 경우가 있다. 예를 들어보자.

 

이체 작업을 해야하는데 A가 B에게 만원을 보낸다고 가정해보면, A의 돈 만원이 차감되고 B의 돈 만원이 추가되어야 한다. 그런데 A의 돈 만원이 차감되는 작업은 성공적으로 수행했는데 B의 돈 만원이 추가되는 작업은 어떠한 이유에서인지 실패했다. 이 경우 커밋을 하면 안되고 롤백을 수행해야한다. 그런데 오토 커밋이 적용되어 있는 경우라면 A의 돈 만원은 차감되고 B의 돈은 그대로인 상황을 마주하게 된다.

 

이런 경우엔 오토 커밋을 꺼야한다. 

 

Rollback

롤백은 트랜잭션이 시작되고 끝나는 시점사이에 일어난 모든 DB에 대한 행위를 이전으로 돌리는 것이다. 어떠한 이유에서인지 트랜잭션 내 어떤 작업이 실패했다면 트랜잭션이란 단위에서 일어난 모든 행위는 전부 다 실패로 돌아가야한다. 이를 원자성이라고 하는데 트랜잭션에서 일어난 모든 행위는 마치 하나인 것처럼 모두 성공하거나 실패해야한다. 

 

Lock

락은 트랜잭션에서 어떤 데이터의 변경이 일어났을 때 그 데이터를 다른 곳에서 접근하려고 하는 경우를 막는 것이다. 예를 들어, A라는 회원의 돈을 세션A가 수정했고 커밋하기 전이라면, 나머지 세션B, C, D, ... 모두 A라는 회원의 돈을 수정할 수 없다. 이는 락을 가지고 있는 세션이 세션A이기 때문이다. 세션A가 락을 반납(커밋하는 시점)하기 전에는 다른 세션에서 해당 데이터를 접근할 수 없다. 

 

 

JPA와 트랜잭션

자 이 개념들을 가지고 Springframework의 트랜잭션 개념을 접목시켜보자.

@Transactional 어노테이션을 달고 있는 메소드가 실행되고 끝나는 시점이 트랜잭션이 시작되고 종료(커밋 또는 롤백)되는 시점이다.

 

그리고 @Transactional 어노테이션이 달린 메서드가 트랜잭션을 시작한다는 것은 다음 명령어를 입력하는 것으로부터 시작하는 것이다.

set autocommit false;

 

왜냐하면, 어떤 SQL문을 날리더라도 그 날리는 순간 커밋이 되는것이 오토 커밋인데, 스프링과 JPA에서 메서드에 달린 @Transactional은 메소드의 시작과 끝이 트랜잭션의 시작과 끝이고 그 메서드안에서 무수히 많은 SQL문을 날릴 수 있고 이것들은 날리면서 바로 커밋되는것이 아니라 모든 로직이 다 끝난 시점에 커밋이 한번에 되는 것이기 때문에 저 명령어를 시작으로 트랜잭션이 시작하는 것이다.

 

그리고 한가지 더 알아야 할 점은 아까 원자성 얘기를 하면서 한 트랜잭션에서 일어난 모든 행위는 모두 성공하거나 모두 실패해야 한다고 했는데 이는 곧 @Transactional 어노테이션은 서비스 계층에서 사용되어야 함을 말한다. 왜냐하면, 서비스 계층에서 트랜잭션이 열리고 닫혀야 그 서비스 단에 비즈니스 로직에서 수행되는 모든 DB에 대한 변경 작업이 어떤 하나라도 실패하면 연관된 모든 작업이 롤백되어야 하고 모든것들이 다 성공하여야 연관된 모든 작업이 커밋되어야 하기 때문.

 

자동 커밋: 만약, 어떠한 설정도 변경하지 않았고 문제없이 모든 작업을 정상 수행했다면 이 트랜잭션은 메소드가 종료되는 시점에 자동 커밋을 수행한다.

 

롤백: 만약, 어떠한 설정도 변경하지 않았고 트랜잭션을 달고 있는 메소드가 로직을 수행하던 중 DB 작업에 문제가 발생하면 이 트랜잭션은 롤백을 수행한다. 롤백은 해당 트랜잭션 단위에서 일어난 모든 행위를 이전으로 돌린다.

 

락: 만약, 어떠한 설정도 변경하지 않았고 트랜잭션A를 달고 있는 메소드가 어떤 데이터에 대한 변경작업을 한 상태에서 메소드가 종료되지 않은 상태라면 다른 쓰레드에서 다른 트랜잭션B를 가지는 메소드가 같은 데이터에 변경 작업을 수행하려고 해도 수행할 수 없다. 이는 트랜잭션A가 트랜잭션을 종료(커밋 또는 롤백)하지 않았기 때문이다.

 

 

내가 이걸 정리한 이유는 나는 이걸 모르는 상태에서 분명 새 레코드를 저장하는 코드라인을 수행했는데 (DB가 컨테이너위에서 실행중이고, 이 DB에 접근하는 스프링 부트 서버는 또 다른 컨테이너 위에서 동작중) 컨테이너 내부로 들어가서 DB를 조회해보니 데이터는 없었다. 이유가 뭔지 몰랐는데, 트랜잭션이 종료되지 않았기 때문에 커밋되지 않은 것이었다. 왜 종료되지 않았는지 몰랐냐면 @Transactional은 속성값으로 propagation이라는 속성을 가지는데 이 속성이 '전이 속성'이다. 즉, 트랜잭션에서 또 다른 트랜잭션이 열릴 때 이 트랜잭션을 합칠것인지 가져다가 사용할것인지 새로 만들것인지에 대한 내용인데, 기본값이 트랜잭션이 있으면 그 트랜잭션을 그대로 사용하기 때문에 트랜잭션이 종료되지 않았다. 이 또한 작업을 수행한 후에 바로 커밋을 적용하거나 트랜잭션을 분리하여 커밋을 바로 적용하거나 하면 된다만, 이런 개념도 전혀 몰랐던 상태였기 때문에 내 스스로 공부하고자 작성했다.

728x90
반응형
LIST

'Spring + DB' 카테고리의 다른 글

Index란? (DB)  (0) 2024.04.05
선언적 트랜잭션(@Transactional) 내부 호출 주의  (2) 2023.12.07
MyBatis  (4) 2023.12.06
JdbcTemplate  (0) 2023.12.06
[Spring/Spring Data JPA] @Transactional  (0) 2023.11.12