OrderController에서 form을 받아서 식별자만 넘겨주는 이유
@PostMapping
public String order(@RequestParam("memberId")Long memberId,@RequestParam("itemId") Long itemId,
@RequestParam("count") int count){
orderService.order(memberId,itemId,count);
return "redirect:/orders";
}
만약 OrderController에서 주문하는 member를 찾아서 service로 넘기는 경우 -> 위의 코드는 Trascational 상태가 아니기 때문에 영속성이 유지가 되지 않게 되어 dirty checking이 처리가 되지 않게 되고 별개로 돌아가게 된다.
-> 만약 예시로 든 member를 꺼내고 service에 넘긴다음 밑의 코드 같이 member의 이름을 바꾸게 된다 치면 안바뀐다고 생각햇는데 아니였다.
@Transactional
public Long order(Member member, Long itemId, int count) {
//엔티티 조회
// Member member = memberRepository.findOne(memberId);
Item item = itemRepository.fineOne(itemId);
member.setName("helloworld");
//배송정보 생성
Delivery delivery = new Delivery();
delivery.setAddress(member.getAddress());
//주문상품 생성
OrderItem orderItem = OrderItem.createOrderItem(item, item.getPrice(), count);
//주문 생성
Order order = Order.createOrder(member, delivery, orderItem);
//주문 저장
orderRespository.save(order);
return order.getId();
}
이게 되는 이유를 찾아보니 Spring 에 open-in-view 때문이였다.
open-in- view는 기본적으로 true의 값을 가지게 되고 말그대로 영속성 컨텍스트를 뷰까지 열어둔다는 의미이다.
이것 때문에 ApiController나 뷰에서도 지연로딩이 가능했던 것.
그다음 Service 계승의 Transcation이 있는 비즈니스 로직을 실행
트랜잭션 AOP 가 동작하면서 영속성 컨텍스트에 트랜잭션을 시작 -> order 메소드를 실행한다.
(여기서 문제 발생) order 메서드가 끝나면 트랜잭션 AOP는 트랜잭션을 커밋하고 영속성 컨텍스트를 플러쉬하게 되어 변경감지가 발생하고 회원 엔티티의 수정 사항을 데이터 베이스에 반영하게 되버리는 것.
현재 문제를 해결하는 단순한 방법으로는 트랜잭션을 수행하는 비즈니스 로직을 먼저 실행하고 엔티티 변경을 진행하면 DB에는 반영이 되지않는다.
트래픽이 적은 경우에는 true로 해서 사용해도 무방하지만 실시간 트래픽이 중요한 애플리케이션에서는 커넥션이 모자랄 수 있게되고 장애가 발생할 수 있다.
지금은 여기까지 해두고 JPA 활용 2편에서 좀 더 다루고 있기 때문에 JPA2활용에서 좀 더 자세히 이해해보자.
책 : 자바 ORM 표준 JPA 프로그래밍
블로그 :
https://catsbi.oopy.io/eedf92ff-8834-458d-86e4-0ed2e01b5971