안녕하세요 여러분 일단고입니다!
날씨가 많이 추워져서 이제 긴팔을 입을 정도가 되었으니…. 겨울이 금방오지 않을까… 여러분 감기 조심하셔야 합니다.
지난번에 ‘트랜잭션의 이해’에 대해 배우고 오늘은 Spring boot에서 해당 트랜잭션을 구현하는
@Transactional 애노테이션에 대해서 알아보겠습니다!
1. 트랜잭션
Spring Boot의 @Transactional 애노테이션에 대해 알기 전 트랜잭션에 대해 간단히 알아봅시다.
트랜잭션은 데이터베이스 작업을 원자적으로 수행하는 논리적 작업 단위입니다.
이는 ACID (원자성, 일관성, 고립성, 지속성) 특성을 준수하며, 데이터베이스 작업 중 에러가 발생하더라도 일관성을 유지하고 롤백할 수 있도록 합니다.
2. @Transactional 애노테이션 : 개념과 기능
Spring Boot에서 @Transactional 애노테이션은 메서드 또는 클래스 레벨에서 사용하여 해당 메서드가 트랜잭션 내에서 실행되도록 지정합니다. 이를 통해 다음과 같은 기능을 수행할 수 있습니다.
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
@Transactional
public void saveProduct(Product product) {
productRepository.delete(product);
productRepository.save(product);
}
}
위의 예시에서 @Transactional 애노테이션이 사용된 saveProduct 메서드는 트랜잭션 내에서 실행되며, 메서드가 호출되는 시점에서 트랜잭션이 시작되고, 메서드의 정상 종료 시점에서 커밋되거나 예외 발생 시 롤백됩니다. 모두 아시겠지만 delete가 성공적으로 수행해도 save가 실패하면 savProduct 메서드 즉, 트랜잭션이 실패한 것으로 보고 delete작업을 rollback시키게 됩니다.
3. @Transactional의 장점
- 코드의 간결성
- @Transactional을 사용하면 개발자는 트랜잭션 관리 코드를 별도로 작성할 필요가 없으므로 코드가 간결해집니다.
- 위 예시 코드를 보면 다른 별다른 코드 없이 메서드에 @Transcationl 코드만 넣어주면 동작하니 코드도 간결하고 가독성도 높아집니다.
- 예외 처리
- @Transactional은 예외가 발생하면 롤백을 수행하게 java 내에 예외사항에 대비하여 데이터 일관성을 보장합니다.
- 중첩 트랜잭션
- 중첩 트랜잭션을 내부적으로 지원하여 복잡한 비즈니스 로직을 효과적으로 처리할 수 있습니다.
4. @Transactional의 원자성과 주의사항
@Transctional을 사용할 때 주의해야 할 점은 다음과 같습니다.
4.1 예외 처리
@Transactional은 기본적으로 런타임 예외 (Unchecked Exception)만 롤백합니다. Checked Exception은 롤백하지 않으므로 주의해야 합니다.
public class DefaultTransactionAttribute extends DefaultTransactionDefinition implements TransactionAttribute {
...
...
...
public boolean rollbackOn(Throwable ex) {
return ex instanceof RuntimeException || ex instanceof Error;
}
}
위 코드는 @Transactional의 내부 동작이 정의된 코드 중 작은 일부입니다. rollback을 하는 조건을 정의하는 곳인데 해당 부분을 보니 RuntimeException에 대해서만 롤백합니다. 즉 해당 예외가 아니라면 rollback을 하지 않게 된다는 것이 중요한 핵심이 됩니다.
Java에서 예외는 크게 Checked Exception, UnChecked Exception으로 나누는데 RuntimeException은 UnChecked Exception으로 rollback이 되지 않는 특징입니다.
Checked Exception까지 rollback 대상에 넣지 않은 이유는 개발자의 실수로 유도된 Checked Exception까지 에러를 강제하면 코드가 복잡해지기 때문에 선택권을 준것 같습니다.
따라서 Checked Exception까지 예외처리 대상에 넣기 위해서는 @Transactional(rollbackFor = Exception.class) 을 사용해주어야 합니다.
4.2 메서드 호출 내에서의 트랜잭션 경계
@Transactional을 사용한 메서드가 내부에서 다른 @Transactional 메서드를 호출할 때 트랜잭션 경계 설정에 주의해야 합니다. 아래는 중첩 트랜잭션의 예시입니다.
@Service
public class OrderService {
@Autowired
private ProductService productService;
@Transactional
public void createOrder(Order order) {
// 주문 처리 로직
// 상품 서비스의 saveProduct 메서드 호출 (내부에서 @Transactional 사용)
productService.saveProduct(order.getProduct());
}
}
부모 트랜잭션에서 호출한 자식 트랜잭션이 실패하면 어떻게 처리할지를 결정하는데 있어 주의를 기울여야 합니다. 어떤 트랜잭션은 성공했지만 다른 트랜잭션은 성공하지 못하는 상황과 그 반대의 상황의 예기치 못하게 발생하기 떄문에 try-catch문 혹은 애노테이션에서 Propagation 설정을 해주어야 합니다.
오늘은 Spring boot에서 DB를 사용할 때 자주 사용하면서도 그 세부내용은 모르고 사용하는 @Transactional 사용에 대한 간단한 주의사항을 중심으로 알아봤습니다.
도움이 되셨나요? 간단한 기초 개념으로 봐주시면 감사하겠습니다.
다음시간에는 오늘 내용의 주의사항 중심으로 rollback, commit 전략을 경우의 수로 보면서 깊게 이야기 해볼까 합니다.
그럼 다음 시간에 만나요.
'Programming' 카테고리의 다른 글
Understanding Interfaces in Go (1) | 2023.10.13 |
---|---|
많이 사용되는 개발 프레임워크 및 라이브러리 (0) | 2023.10.13 |
[Mybatis] #{}과 ${}의 차이 (0) | 2023.10.05 |
Go 언어에서의 Receiver와 메서드 (0) | 2023.09.30 |
패러다임에 따른 개발 언어의 분류와 특징 (0) | 2023.09.27 |
댓글