2023년 1월 1일
08:00 AM
Buffering ...

최근 글 👑

[스프링] 트랜잭션의 이해와 활용,@Transactional 원리 - 기록만이 살길

2023. 6. 14. 21:18ㆍ[스프링 DB]/트랜잭션

 

[🍊트랜잭션의 이해]

 

 

[트랜잭션 이란 무엇인가?] - 트랜잭션의 이해 (tistory.com)

 

[트랜잭션 이란 무엇인가?] - 트랜잭션의 이해

[🍓트랜잭션의 정의] 트랜잭션(Transaction)은 데이베이스의 상태를 변화시키는 하나의 논리적 기능을 수행하기 위한 작업의 단위 또는 한꺼번의 수행되어야 하는 일련의 과정이다. 이렇게 만들어

thaud153.tistory.com

 

트랜잭션의 이해는 이 글을 본다면 완벽히 이해가 될 것 이다.

 

 

[🍊스프링 트랜잭션 적용]

 

스프링의 트랜잭션을 적용하는 방법은 여러가지가 있는데

대표적으로 스프링이 제공하는 

 

@Transatcial 어노테이션을 사용하면 되지만

이것을 사용하기전에 트랜잭션의 깊은 이해가 필요할 것 이다.

 

[🍊Connection을  통한 트랜잭션]

 

DataSource를 통하여 한번 트랜잭션을 작성해보자.

 

저 글을 읽고 온다면 나는 계좌송금을 통한 서비스 로직을 작성할 것 이다.

 

 

 

이 로직을 본다면 계좌 송금 로직이다.

Connection을 받고 송금 할 사람 , 송금 받을 사람 , 금액을 매개변수로 받았다.

저기 체크한 부분이 트랜잭션을 시작하는 것 이다.

 

connection.setAutoCommit(false);

 

이 setAutoCommit을 실행한다면 이때부터 트랜잭션은 시작되는 것 이다.

여기서 true를 넣을 경우 Sql이 실행될때마다 Commit이 되는 것 이다.

그렇게 되면 트랜잭션을 하는 의미가 없기 때문에 false로 지정해줬다.

 

 

또한 

 

}catch (RuntimeException e){
    connection.rollback();
}


이 Catch절로 만약 RuntimeException이 뜬다면 이 로직을 RollBack 시키도록 적용했다.

 

 

connection.commit();

 

그 후 에러가 뜨지 않는다면 정상적인 코드임으로 Commit을 적용 시켰다.

 

이렇게 트랜잭션은 RollBack과 Commit 이 두 가지의 상태를 가지고 있다.

 

 

 

 

그 후 로직이 돈 다음 정상적으로 로직이 성공되면 DB에 성공적으로 저장 될 것 이다.

하지만 이 코드가 Commit을 만나기전까지 오류가 뜬다면 이 코드는 RollBack되어 DB에 저장이 되지 않는다.

한번 확인 해보자.

 

 

 

 

 

 

일단 DB에는 김좌진과 홍길동에게 각각 만원씩 저장되있는걸 볼 수 있다.

 

 

 

 

테스트 코드에서 보낸이 홍길동 , 받는이 김좌진 금액은 3천원으로 보냈다.

이 코드의 경우 정상작동되는 코드임으로 적상적으로 DB에 저장 될 것 이다.

 

 

 

 

확인 해본다면 김좌진에게 13000원 홍길동에게 7000원이 정상적으로 입금되는 것을 볼 수 있다.

 

 

 

[🍊트랜잭션의 에러 적용]

 

만약 트랜잭션이 없고 에러가 터진다면 어떻게 될까?

 

예를들어 보자.

 

 

 

저기 동그라미 친 부분에 에러가 뜬다고 가정해보자.

홍길동이라는 사람은 3천원을 보냈고 보내는 과정 중 에러가 뜬 상황이다.

그렇게 된다면 홍길동의 - 3000원은 정상적으로 DB에 적용 될 것이다.

 

하지만 받는사람의 김좌진은 어떻게 되는 가?

한번 테스트 코드로 확인 해보도록 하자.

 

 

 

 

 

 

나는 이러한 메서드를 만들어서 저기 코드에 적용해보겠다.

 

 

 

 

 

 

이렇게 홍길동이 3천원을 보내고 받는 과정에서 에러를 터뜨린다면 어떻게 될까??

 

 

 

 

 

다시 DB에는 각 각 만원씩으로 맞췄다.

 

 

 

 

이렇게 테스트 코드에 3천원을 보내는 걸 적용해봤다.

 

 

 

 

일단은 코드대로 RuntimeException이 터졌다.

그렇다면 DB에 있는 값들은 어떤식으로 저장되는가?

 

 

 

 

 

이렇게 트랜잭션이 적용이 되지 않았을땐

돈을 보냈지만 홍길동의 돈은 없어졌지만 김좌진의 돈은 입금되지 않는 것을 볼 수 있다.

 

이렇게 트랜잭션이 없다면 코드가 동작하는 와중에 에러가 터진다면

그 일련의 과정 중 도중에 실행되다가 에러가 터져서 멈추는 것 이다.

 

만약 이게 실제 상황이라면 정말 아찔한 상황이다.

 

하지만 트랜잭션을 적용한다면 어떻게 될까?

 

 

 

다시 이렇게 서비스 로직에 이 트랜잭션을 적용 시켰다.

 

 그 후 DB에 돈도 각 각 만원으로 다시 맞추었다.

 

 

 

 

 

그 후 테스트 코드로 다시 삼천원을 보내보자.

 

 

 

 

 

 

 

일단은 정상적으로 에러가 터지는 것을 볼 수 있다.

그렇다면 DB에 저장에 되어있는 돈은 어떻게 될 것인가?

 

 

 

 

 

이렇게 정상적으로 로직이 되돌아 오는걸 볼 수 있다.

 

 

 

 

[🍊Connection의 문제점]

 

 

일단 트랜잭션은 기본적으로 서비스 로직에 작성해야 한다.

또한 서비스 로직은 다른 클래스와 의존해서는 안된다.

하지만 서비스 로직을 본다면 Connection이라는 클래스에 의존하고 있다.

트랜잭션을 함에따라 Connection을 의존하게 될 수 밖에없다.

 

 

이렇게 MVC패턴에서는 서비스 로직이 핵심이기 때문에 서비스 로직은 어떠한 의존이 있어선 안된다.

 

그렇다면 이것을 해결할려면 어떻게 해야할까?

 

 

[🍊스프링 @Transactional 사용]

 

그 답은 스프링이 제공하는 @Transactional에 답이있다.

스프링은 이러한 코드를 이 어노테이션 하나로 그 답을 해결했다.

 

사용법은 간단하다

 

메서드나 클래스에 @Transactional을 적용해주면 된다.

 

이 어노테이션만 넣는다면 우리가 했던 모든 일련의 과정들을 해결할 수 있다.

 

메서드에 @Transactional을 붙인다면 메서드만 트랜잭션을 적용하고

클래스에 @Transactional 붙인다면 클래스에 있는 메서드 전부 트랜잭션을 적용한다.

 

 

이렇듯 내가 트랜잭션을 적용하고 싶은 로직에 어노테이션을 붙이기만 한다면

트랜잭션이 적용 된다.

 

 

예제로 보자

 

 

 

 

아까와 같은 코드에 이 트랜잭션을 적용했다.

 

 

 

테스트 코드도 아까와 같이 작성했다. 그렇다면 결과는 어떻게 될까??

 

 

 

 

 

일단은 테스트 코드를 실행하니 내가 설정한 오류가 난 것을 볼 수 있다.

 

 

 

 

DB를 확인해보니 정상적으로 트랜잭션이 적용되는 것을 볼 수 있다.

이렇듯 @Transactional로 우리가 고민했던 모든 것들이 해결되었다.

또한 이 트랜잭션 어노테이션으로 매우 쉽게 트랜잭션을 적용 할 수 있다.

 

또한 우리가 직접 트랜잭션을 사용했을 때는 우리가 catch로 지정한 예외만

트랜잭션이 적용된다.

 

Exception으로 잡아도 되지만

 

그렇게 된다면 어느곳에서 예외가 터진지 쉽게 알 수 없기 때문에 어려움이 있다.

하지만 이 트랜잭션 어노테이션으로 이 문제를 해결 할 수 있다.

[주의]

 

트랜잭션은 체크 예외일때는 트랜잭션을 적용하지 않는다.

체크 예외라 하면은 Runtime을 제외한 모든 예외이며

언체크예외는 Runtime예외를 말한다.

 

Check예외 일때는 트랜잭션이 적용되지 않으며

Check 예외는 비지니스 예외라고 하고 시스템 장애는 없지만비지니스적으로 예외가 터진 경우에 발생하기 때문에 트랜잭션은 시스템에 장애가 없다고 판단 해 Commit을 한다.

 

언체크예외는

대부분 시스템 장애가 나서 발생하는 오류를 뜻하는데

예를들어 NullPointException등이 있다.

그렇기 때문에 트랜잭션은 언체크 예외 발생 시 시스템 오류라고 판단해

RollBack을 한다.

 

 

UnCheck예외 일때는 트랜잭션이 적용된다.

 

 

 

 

 

[🍓정리]

 

트랜잭션은 DB를 사용함에 있어서 핵심적인 기술이다.

 

이 트랜잭션은 서비스로직에 사용해야 하며

 

99.9퍼센트는 @Transactional을 사용하여 트랜잭션을 작성한다.

 

@Transactional클래스에 붙인다면 클래스 내에 있는 메서드 전부 트랜잭션이 적용되며

@Transactional메서드에 붙인다면 해당 메서드만 트랜잭션이 적용된다.

 

또한 TransactionTemple이나 Connection등 많은 템플릿이 트랜잭션을 적용한다.

하지만 대부분은 @Transactional을 사용하고 이 어노테이션을 사용하기 위해서

트랜잭션이 어떠한 원리로 적용되는지 알아보았다.