JPA/JPA 활용
-
OSIV와 성능 최적화JPA/JPA 활용 2023. 8. 11. 14:02
OSIV (Open Session In View) 스프링부트에서 트랜잭션을 시작할 때 데이터베이스 커넥션을 가지고온다. -> 데이터베이스 커넥션 : 한 번에 접근할 수 있는 쓰레드 풀 같은 커넥션 이 때 OSIV가 켜져있으면 트랜잭션이 끝나고 컨트롤러 계층까지 가도 데이터베이스 커넥션을 반환하지 않는다. 그 이유는 Lazy 로딩을 생각하면 데이터가 필요한 시점에 프록시 객체를 db에서 가져오기 때문이다. 영속성 컨텍스트가 데이터베이스를 계속 붙잡고 있어야 한다. api가 유저한테 반환이 되고 response가 나갈 때 까지 데이터베이스 커넥션을 붙잡고 있는 것이다. OSIV는 기본이 true, 켜져있는 상태이다. OSIV 장점 지연 로딩은 영속성 컨텍스트가 살아있어야 하고, 영속성 컨텍스트는 기본적으로 ..
-
컬렉션 조회 최적화 3 - 페이징과 한계점 돌파JPA/JPA 활용 2023. 8. 10. 21:30
컬렉션을 페치 조인하면 일대 다 조인이기 때문에 페이징이 불가능하다. 하이버네이트 6에서부터 중복을 제거해주긴 해지만 일대다 매핑을 하면 기대했던 것보다 데이터 양이 배로 늘어날 수 있다. 일대 다에서 1을 기준으로 페이징을 해야하는데 다수 쪽을 기준으로 페이징을 하면 문제인 것이다. Order를 기준으로 페이징을 하고 싶어도 다수쪽인 OrderItem을 조인해버리면 OrderItem이 기준이 될 수 있다. 하이버네이트는 모든 데이터를 읽어온 다음 메모리에서 페이징을 하는데, 실제로 많은 데이터를 페이징한다면 메모리 오류가 날 것이다. 장애가 생길 수 있으므로 되도록 사용하지 않는 것이 좋다. 최적화 방법 1. 먼저 일대일, 다대일 관계에서는 페치 조인을 적용해도 상관이 없으므로 페치 조인을 한다. @T..
-
컬렉션 조회 최적화 2 - fetch join으로 최적화JPA/JPA 활용 2023. 8. 10. 16:35
OrderRepository에 finAllWithItem 추가 public List findAllWithItem() { return em.createQuery("select o from Order o" + " join fetch o.member m" + " join fetch o.delivery d" + " join fetch o.orderItems oi" + " join fetch oi.item i", Order.class) .getResultList(); } 컨트롤러 @GetMapping("/api/v3/orders") public List ordersV3() { List orders = orderRepository.findAllWithItem(); List collect = orders.stream..
-
컬렉션 조회 최적화 1 - 페치 조인을 안 했을 시JPA/JPA 활용 2023. 8. 10. 15:57
@OneToMany에서의 최적화를 하는 방법은 엔티티 조회 최적화보다 조금 더 까다롭다. 여기서도 이전 방식처럼 성능이 안 나오는 것부터 점진적으로 발전해나가면서 할 예정이다. 1. 엔티티를 그대로 노출 @GetMapping("/api/v1/orders") public List ordersV1() { List all = orderRepository.findAllByString(new OrderSearch()); for (Order order : all) { order.getMember().getName(); order.getDelivery().getAddress(); List orderItems = order.getOrderItems(); orderItems.stream().forEach(o -> o.g..
-
간단한 주문조회 API - 지연 로딩과 조회 성능 최적화(2)JPA/JPA 활용 2023. 7. 11. 18:16
저번 포스팅에서 Order 조회 버전 1과 2를 했는데, 1에서는 엔티티를 그대로 사용해서 문제점이 있었고, 2에서는 Lazy 로딩때문에 쿼리가 너무 많이 호출되는 문제점이 있었다. 이번에 Version 3에서는 fetch join으로 성능 최적화를 진행할 것이다. Version3 orderRepository에 finAllWithMemberDelivery() 메서드 추가 public List findAllWithMemberDelivery() { return em.createQuery( "select o from Order o" + " join fetch o.member m" + // order 가져올 때 멤버까지 한방 쿼리로 가져오는 'join fetch' " join fetch o.delivery d"..
-
간단한 주문조회 API - 지연 로딩과 조회 성능 최적화JPA/JPA 활용 2023. 7. 11. 18:15
지연 로딩 때문에 발생하는 성능 문제를 단게적으로 해결하는 것이다. 버전을 1부터 4까지 늘리면서 잘 실수하는 부분을 조금씩 개선해나가는 것이다. 실험용 초기 데이터 @Component @Transactional @RequiredArgsConstructor static class InitService { private final EntityManager em; public void dbInit1() { Member member = new Member(); member.setName("userA"); member.setAddress(new Address("서울", "1", "1111")); em.persist(member); // 영속상태로 만듦 Book book1 = new Book(); book1.se..
-
회원 조회 APIJPA/JPA 활용 2023. 7. 11. 18:15
회원 조회를 할 수 있는 컨트롤러이다. @RestController // api 설계할 때에는 RestController 사용 @RequiredArgsConstructor public class MemberApiController { private final MemberService memberService; @GetMapping("/api/v1/members") // 조회는 GetMapping public List membersV1() { return memberService.findMembers(); } @GetMapping("/api/v2/members") public Result memberV2() { List findMembers = memberService.findMembers(); List ..
-
회원 수정 APIJPA/JPA 활용 2023. 7. 11. 18:14
(등록을 진행한 컨트롤러와 같은 컨트롤러에 등록 클래스 아래에 만들었음) @PutMapping을 이용한 회원 이름 수정 @RestController @RequiredArgsConstructor public class MemberApiController { @PutMapping("api/v2/members/{id}") public UpdateMemberResponse updateMemberV2(@PathVariable("id") Long id, @RequestBody @Valid UpdateMemberRequest request) { memberService.update(id, request.getName()); Member findMember = memberService.findOne(id); retur..