Hansel
스프링 / 트랜잭션 관리 & 예외 본문
일반적으로 트랜잭션 적용이 필요한 메서드 및 클래스에는 위와 같이 @Transactional 애노테이션을 붙여 사용했다.
데이터베이스에서 트랜잭션이 무엇을 의미하는지는 알았지만 저 애노테이션이 어떤 역할을 하는지 왜 필요한지에 대해서는 잘 알지 못했다.
위와 같은 애노테이션을 선언적 트랜잭션 관리 방법이라 한다.
선언적 트랜잭션 관리(Declarative Transaction Management)
간단히 @Transactional을 추가해 매우 편리하게 트랜잭션을 적용하는 것을 선언적 트랜잭션 관리라 한다.
이름 그대로 해당 로직에 트랜잭션을 적용하겠다 라고 어딘가에 선언하기만 하면 트랜잭션이 적용되는
방식이다.
이게 어떤 식으로 동작하는지는 스프링 AOP를 학습해야하는데 아직은 학습하지 않았기 때문에 우선은 트랜잭션 적용에 필요하다 정도로만 알고 넘어가려 한다.
트랜잭션이 실제로 적용되는지 확인
선언적 트랜잭션을 통해 실제로 트랜잭션이 적용되는지 확인할 필요가 있다.
TransactionSynchronizationManager를 통해 현재 적용되는 트랜잭션의 다양한 설정 및 상태를 확인할 수 있다.
ReadOnly인지, 격리레벨은 어느정도인지, 트랜잭션이 적용되고 있는지 등을 확인할 수 있다.
프록시 호출?
트랜잭셔널 애노테이션을 사용하면 스프링의 트랜잭션 AOP가 적용된다.
해당 객체를 상속받은 프록시 객체에서 요청을 받아 트랜잭션을 처리하고 실제 객체를 호출하는 방식이라 한다.
결국 트랜잭션을 적용하려면 항상 프록시 객체를 통해야 하는데 @Transactional이 없으면 트랜잭션 AOP 적용 대상이 아니게 되고, 결과적으로 프록시 객체가 스프링 빈에 등록이 안된다.
이로 인한 문제점은 프로젝트를 하면서 몇번 경험해 본 적이 있다.
위 사진은 정상적인 처리를 보여준다.
@Transactional이 있어 프록시 객체는 트랜잭션을 적용하고 메서드를 수행한다.
external 메서드를 호출
한 경우다.
애노테이션이 없는 external, 있는 internal 모두 트랜잭션이 적용되지 않았다.
external에 @transactional이 없기 때문에 트랜잭션을 적용하지 않고 프록시가 아닌 실제 객체에서 처리한다.
결국 internal까지 연달아 트랜잭션이 적용되지 않았다.
해결 방법은 별도의 클래스를 생성하거나, @Transactional을 붙여주는 것이다.
이 경우 다음과 같은 순서를 따른다.
1. 클라이언트인 테스트 코드는 callService.external() 을 호출한다.
2. callService 는 실제 callService 객체 인스턴스이다.
3. callService 는 주입 받은 internalService.internal() 을 호출한다.
4. internalService 는 트랜잭션 프록시이다. internal() 메서드에 @Transactional 이 붙어
있으므로 트랜잭션 프록시는 트랜잭션을 적용한다.
5. 트랜잭션 적용 후 실제 internalService 객체 인스턴스의 internal() 을 호출한다.
이건 external에도 트랜잭션 어노테이션을 붙여주는 방식이다.
하지만 외부 메서드에서 트랜잭션 처리가 필요하지 않은 경우에도 트랜잭션이 적용되어 효율적인 방법은 아니다.
트랜잭션 예외처리
예외 발생시 스프링 트랜잭션의 기본 정책은 다음과 같다.
언체크 예외인 RuntimeException , Error 와 그 하위 예외가 발생하면 롤백한다.
체크 예외인 Exception 과 그 하위 예외들은 커밋한다.
체크 예외에서도 롤백하고 싶다면
rollbackFor 옵션을 사용하면 된다.
언체크 예외에서 롤백하고 싶지 않다면
noRollbackFor 옵션을 사용하면 된다.
체크예외는 throws나 try-catch로 반드시 처리해야 하는 예외들을 말한다.
언체크 예외는 잡아서 처리하지 않아도 throws 를 생략할 수 있다. 대표적으로 NullPointer 예외가 있다.
스프링 기본적으로 체크 예외는 비즈니스 의미가 있을 때 사용하고, 런타임(언체크) 예외는 복구 불가능한
예외로 가정한다.
따라서 로직에 맞게 체크, 언체크(런타임) 예외를 적절히 설정하고 그에 맞는 로직을 작성해주는 것이 좋다.
예를 들어 서버에서 파일을 불러와 첨부하고 글을 작성할 때 파일이 잘못된 경우 FileNotFoundException이 발생했다고 치자
이 경우 예외를 잡아 파일 없이 글이 작성되도록 로직을 수행하는 식으로 유연하게 대처할 수 있을것이다.
'Spring > 기초' 카테고리의 다른 글
스프링 부트 / 야매 게시판 만들기 4 (0) | 2022.03.05 |
---|---|
스프링 부트 / 야매 게시판 만들기 3 (0) | 2022.03.05 |
스프링 부트 / 야매 게시판 만들기 2 (0) | 2022.03.05 |
스프링 부트 / 야매 게시판 만들기 1 (0) | 2022.03.05 |
스프링부트 기초 / 변경 감지와 병합 (0) | 2022.02.21 |