Transaction
이란 db에 접근하는 작업의 단위를 의미한다.
계좌 서비스가 있을 때 a가 b에게 송금하는 로직을 예시로 들어보자.
a가 b에게 10000원을 송금한다면, 아래의 두 로직으로 세분화할 수 있다.
이 두 로직의 묶음, a가 b에게 송금하기 위한 작업의 단위를 트랜잭션이라고 본다.
Transaction
은 다음 네 가지의 특징을 가진다.
Commit은 트랜잭션을 데이터베이스에 영구적으로 반영하는 것을 의미한다.
Rollback은 Commit이전에 데이터 베이스의 상태를 트랜잭션이 수행되기 전의 상태로 되돌리는 것을 의미한다.
트랜잭션 도중에 에러가 발생한다면, 원자성에 따라 중간까지 반영된 트랜잭션이 전부 반영되지 않게 변경해야한다. 이 경우에 Rollback이 필요하다.
트랜잭션에 대한 처리를 하는 클래스, 메서드단에 @Transactional
을 붙여 트랜잭션임을 선언할 수 있다.
@Transactional
이 붙으면 프록시 객체를 생성해 트랜잭션에 대한 처리를 자동으로 수행한다.
보통 비즈니스 로직을 단위로 처리하는 서비스단에 @Transactional
이 붙는다.
클래스와 메서드단에 전부 @Transactional
이 붙어져있다면, 메서드단에 붙여진 @Transactional
이 우선순위를 가진다.
@Transactional
이 붙은 메서드는 도중에 uncheckedException
이 발생하면 Rollback을 수행한다.
@Transactional
의 옵션은 크게 다섯 가지가 존재한다.
이 중 이번 미션에서는 readOnly옵션을 사용해보았다. 이번 포스팅에서는 readOnly 옵션에 대해서만 정리해보도록 하겠다.
트랜잭션이 INSERT, UPDATE, DELETE 명령어를 사용하지 않고, READ 명령어를 사용할 때 적용할 수 있는 옵션이다.
@Transactional
@Service
public class CartItemService {
private final ProductRepository productRepository;
private final CartItemRepository cartItemRepository;
public CartItemService(ProductRepository productRepository, CartItemRepository cartItemRepository) {
this.productRepository = productRepository;
this.cartItemRepository = cartItemRepository;
}
@Transactional(readOnly = true) // 조회 로직에는 readOnly 옵션 설정
public List<CartItemResponse> findByMember(Member member) {
List<CartItem> cartItems = cartItemRepository.findCartItemsByMemberId(member.getId());
ModelSortHelper.sortByIdInDescending(cartItems);
return cartItems.stream().map(CartItemResponse::from).collect(Collectors.toList());
}
public Long add(Member member, CartItemRequest cartItemRequest) {
Product product = productRepository.findById(cartItemRequest.getProductId());
return cartItemRepository.add(new CartItem(member, product));
}
...
}
이번 미션에서는 Mysql을 사용해 데이터베이스를 연동했는데, Mysql의 엔진인 InnoDB의 경우는 readOnly을 true로 설정하면 트랜잭션 ID를 설정하는 오버헤드를 피할 수 있다고 한다. 불필요한 트랜잭션 ID를 제거하면 조회 쿼리를 날릴 때 마다 참조되는 내부 데이터의 크기가 줄어든다고 한다. 참고 링크
트랜잭션 ID는 테이블의 각 행과 연관된 내부 필드로, INSERT, UPDATE, DELETE에 의해 변경되는 필드이며 Lock된 행을 기록한다고 한다. 여기서는 INSERT, UPDATE, DELETE 명령어를 할 때만 필요한 필드라고 이해하고 넘어가자.
h2의 경우에는 readOnly 옵션이 있어도 아무런 행동을 취하지 않는다고 하자. 자기가 사용하는 데이터베이스 엔진이 readOnly시 어떻게 작동하는 지를 파악해서 사용하도록 하자.