728x90
반응형
SMALL
학습내용
- 롤백과 커밋
- 트랜잭션 롤백 전략
- 부분커밋 (entityManager)
학습정리
1.롤백과 커밋
커밋
트랜잭션 작업이 성공적으로 완료 된 경우 변경 사항을 영구적으로 저장
원리 예제코드
@Transactional public void sellProduct(Long productId, int quantity) { // 상품 조회: 존재하지 않으면 예외 발생 Product product = productRepository.findById(productId) .orElseThrow(() -> new ServiceException(ServiceExceptionCode.NOT_FOUND_PRODUCT)); // 재고 차감: 엔티티 내 reduceStock 메서드를 활용 product.reduceStock(quantity); // 변경 사항 저장: 트랜잭션 커밋 시점에 DB에 반영됨 productRepository.save(product); }
롤백
트랜잭션 작업이 실패시 모든 작업을 취소하고 작업 전 상태로 되돌림
원리 예제코드
@Transactional public void sellProductWithError(Long productId, int quantity) { // 상품 조회 Product product = productRepository.findById(productId) .orElseThrow(() -> new ServiceException(ServiceExceptionCode.NOT_FOUND_PRODUCT)); // 재고 부족 체크: 재고가 부족하면 예외 발생하여 트랜잭션 롤백 if (product.getStock() < quantity) { throw new ServiceException(ServiceExceptionCode.OUT_OF_STOCK_PRODUCT); } // 재고 차감 product.reduceStock(quantity); // 변경 사항 저장: 예외가 없으면 커밋되어 DB에 반영됨 productRepository.save(product); }
2. 트랜잭션 롤백 전략
체크 예외(Checked Exception)
컴파일시에 반드시 예외 처리가 요구 됨
Spring에서는 체크예외 발생시에도 트랜잭션 롤백하지 않음
예제코드
//checked예외는 발생하면 롤백이 안됨 //rollbackFor을 사용하면 해당 예외가 발생하면 롤백처리 됨 //메서드에서 throws가 필수면 보통 체크드 예외 @Transactional(rollbackFor = CustomCheckedException.class) public void updateProductPrice(Long productId, BigDecimal newPrice) throws CustomCheckedException { Product product = productRepository.findById(productId) .orElseThrow(() -> new ServiceException(ServiceExceptionCode.NOT_FOUND_PRODUCT)); product.setPrice(newPrice); if (newPrice.compareTo(BigDecimal.ZERO) < 0) { throw new CustomCheckedException("가격은 0보다 커야합니다."); } productRepository.save(product); }
언체크 예외(UnChecked Exception)
런타임 시 발생하며, 강제 처리가 요구되지 않음
Spring에서는 언체크예외 발생시 트랜잭션을 롤백함.
//unchecked예외는 발생하면 무조건 롤백됨 //noRollbackFor을 사용해서 롤백되지 않도록 처리 @Transactional(noRollbackFor = IllegalArgumentException.class) public void reduceProductStockNoRollback(Long productId, Integer quantity) { Product product = productRepository.findById(productId) .orElseThrow(() -> new ServiceException(ServiceExceptionCode.NOT_FOUND_PRODUCT)); product.reduceStock(quantity); productRepository.save(product); if (product.getStock() < quantity) { throw new IllegalArgumentException("재고가 부족합니다."); } }
3. 부분 커밋
예시코드
@Service public class ProductBatchService { @PersistenceContext private EntityManager entityManager; /** * 대량의 제품 목록에 대해 재고를 감소시키는 작업을 배치 단위로 처리합니다. * 각 배치가 끝날 때마다 flush()와 clear()를 호출하여 메모리 사용량을 최적화합니다. */ @Transactional public void batchUpdateProductStock(List<Product> productList, int stockDecrease) { int batchSize = 10; for (int i = 0; i < productList.size(); i++) { Product product = productList.get(i); // 판매 후 재고 감소 처리 product.reduceStock(stockDecrease); entityManager.merge(product); // 배치 단위마다 커밋 및 영속성 컨텍스트 초기화 if ((i + 1) % batchSize == 0) { flushAndClear(); } } // 잔여 데이터 처리 flushAndClear(); } private void flushAndClear() { entityManager.flush(); // 변경 사항을 데이터베이스에 반영 entityManager.clear(); // 영속성 컨텍스트 초기화 (캐시된 엔티티 제거) } }
ps. 금일에는 트랜잭션의 롤백 전략을 배웠는데 이번 주에 트랜잭션에 대해서 깊이 배우고
어떤식으로 사용해야하는지 자세히 배운 것 같아서 좋았다.
728x90
반응형
LIST
'TIL' 카테고리의 다른 글
7_5.성능 검증을 위한 NGrinder 설정과 실습 (0) | 2025.02.10 |
---|---|
7_4.트랜잭션 예외 처리와 외부 API 연동 실습 (0) | 2025.02.09 |
7_2.트랜잭션 전파 옵션과 DB Read/Write 분리 (0) | 2025.02.07 |
7_1.트랜잭션 개념과 선언적/프로그래밍 방식 비교 (0) | 2025.02.04 |
6_5.데이터베이스 기반 작업 큐 실습 (0) | 2025.02.04 |