실전! 스프링 데이터 JPA - 섹션 6~8
·
JPA
사용자 정의 레포지토리필요한 이유개발을 하다보면 기본적인 네이밍 메서드, @Query 어노테이션 안에 간단한 쿼리문으로 구현할 수 없는 복잡한 동적 쿼리(Querydsl 사용) 등이 필요한 상황이 존재한다. 하지만 Spring data JPA가 제공하는 인터페이스에서는 동적쿼리를 구현할 수 없다. 이때, 사용하는 것이 사용자 정의 레포지토리이다.구현 방법// 사용자 정의 인터페이스public interface MemberRepositoryCustom { List findMemberCustom();}// 사용자 정의 인터페이스의 구현체@RequiredArgsConstructorpublic class MemberRepositoryImpl implements MemberRepositoryCustom {..
실전! 스프링 데이터 JPA - 섹션 1~5
·
JPA
공통 인터페이스 구성엔티티의 기본생성자기본생성자가 필요한 이유JPA 구현체마다 스펙이 조금 달라서 기본 생성자를 만들지 않아도 정상적으로 작동하는 경우가 있지만, ’엔티티에는 기본 생성자가 있어야 한다’가 공식 스펙이기 때문에 반드시 기본 생성자를 만들어주는 것이 좋다. 그렇다면 JPA는 왜 엔티티에 기본 생성자를 만들도록 강제하고 있을까?JPA는 데이터를 DB에서 조회해 온 뒤 객체를 생성할 때 **Reflection(리플렉션)**을 사용하기 때문이다. 리플렉션은 클래스 이름만 알면 생성자, 필드, 메서드 등 클래스의 모든 정보에 접근이 가능하다. 하지만 리플렉션이 가져올 수 없는 정보가 있는데 바로 ’생성자의 매개변수 정보’다. 때문에 리플렉션으로 생성할 객체에 모든 필드를 받는 생성자가 있더라도 리..
실전! 스프링 부트와 JPA 활용 2 - 섹션 5~6
·
JPA
컬렉션 조회(OneToMany) 최적화Fetch Join의 한계2개 이상의 컬렉션 fetch join이 불가능하다. 컬렉션 페치 조인은 1개만 사용할 수 있다. 2개 이상의 컬렉션을 fetch join하게 된다면, 카테시안 곱으로 처리하기 때문에 너무 많은 값이 메모리로 들어와 MultipleBagFetchException이 발생하게 된다.컬렉션 fetch join일 경우, 페이징이 불가능하다. 조인 시에 ‘多’ 엔티티의 데이터 개수에 맞추어 데이터가 중복되어 생성되기 때문에 페이징 기준이 틀어져 페이징이 불가능하다. 엄밀히 말하면, 가능하지만 절대 페이징 처리를 해서는 안된다. 컬렉션 페치 조인 시 페이징처리를 하게 되면, 하이버네이트는 경고 로그를 남기면서 모든 데이터를 DB에서 읽어오고 메모리에서 ..
실전! 스프링 부트와 JPA 활용 2 - 섹션 1~4
·
JPA
엔티티를 직접 노출하지 마라@GetMapping("/api/v1/members")public List membersV1() { return memberService.findMembers();}위의 코드처럼 엔티티를 직접적으로 노출하는 것은 많은 문제를 발생시킬 수 있다. 엔티티를 외부에 바로 노출시킬 경우, 엔티티에 변경이 생기면 api의 스펙 자체가 모두 변경이 되고 이는 곧 오류 발생의 원인이 된다. 즉, 화면에 종속적인 api가 만들어지는 것이다. 때문에 엔티티를 바로 노출시키는 것보다는 dto를 활용하여 필요한 것만 노출시켜야 한다.xToOne 관계에서의 성능 최적화순환 참조양방향 연관관계에서 엔티티를 직접 노출하게 되면 순환 참조 문제가 발생할 수 있다. 순환 참조란 무엇일까?순환 참조란,..
실전! 스프링 부트와 JPA 활용1 - 섹션 3~7
·
JPA
애플리케이션 아키텍쳐계층형 구조controller : 웹 계층service : 비즈니스 로직, 트랜잭션 처리repository : JPA를 직접 사용하는 계층, 엔티티 매니저 사용domain : 엔티티가 모여 있는 계층, 모든 계층에서 사용회원 서비스 개발@Service@Transactional(readOnly = true)@RequiredArgsConstructorpublic class MemberService { private final MemberRepository memberRepository; @Transactional public Long join(Member member) { validateDuplicateMember(member); memberRep..
실전! 스프링 부트와 JPA 활용1 - 섹션 1~2
·
JPA
섹션 1@Transactional@Transactional 어노테이션이 test code에 있을 경우, 테스트가 종료되면 자동으로 Rollback을 수행하여 데이터베이스에 데이터가 존재하지 않도록 한다. 반복적인 테스트 수행을 위해 Rollback 하는 것이다. 만약 테스트를 수행하고 DB에 데이터가 담겨있는 것을 확인하고 싶다면 @Rollback(false) 어노테이션 사용하여 Rollback을 취소할 수 있다.Dependency로그창을 보면 쿼리 파라미터는 ?로 찍히고 있다. 이를 실제 값으로 대신 보고 싶다면 아래 의존성을 추가해야한다.implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.6.2'다만, 쿼리 파라미터를 로그로 남기..
자바 ORM 표준 JPA 프로그래밍 - 섹션 10~11
·
JPA
섹션 10, 11. 객체 지향 쿼리 언어JPQL 문법TypeQuery와 QueryTypeQuery는 반환 타입이 명확할 때 사용하는 반면, Query는 반환 타입이 명확하지 않을 때 사용한다.// TypeQueryTypedQuery query = em.createQuery("SELECT m FROM Member m", Member.class);// QueryQuery query = em.createQuery("SELECT m.username, m.age FROM Member m");위의 코드를 살펴보자. 첫 번째 줄의 경우, 반환 타입이 Member임이 자명하다. 때문에 이 경우에는 TypeQuery를 사용해도 된다. 하지만 두 번째의 경우, username은 String 타입이지만 age는 Int 타입..
자바 ORM 표준 JPA 프로그래밍 - 섹션 8~9
·
JPA
섹션 8. 프록시와 연관관계 관리프록시 (Proxy)프록시 객체 (Proxy Object)🍀 프록시 객체는 엔티티의 실제 데이터를 데이터베이스에서 가져오는 시점을 지연시키기 위해 원본(타겟) 객체를 대신해서 호출될 가짜 객체이다.프록시 객체는 실제 클래스(엔티티)를 상속 받아서 만들어지며 클라이언트 코드와 실제 데이터베이스에서 로드된 엔티티 객체(타겟 객체) 사이에 위치한다. 때문에 클라이언트는 실제 엔티티 객체에 직접 접근하지 않고, 프록시 객체를 통해 간접적으로 접근하게 된다. 즉, 프록시 객체는 실제 객체의 참조(target)값을 보관하며 타겟 클래스와 겉모양이 같은 껍데기일 뿐이다. 관계를 쉽게 비유하자면 타겟 객체를 집 주인이라고 생각했을 때, 프록시 객체는 집 주인을 대신해서 계약을 요청받는..
자바 ORM 표준 JPA 프로그래밍 - 섹션 5~7
·
JPA
섹션 5, 6. 연관관계 매핑연관관계 주인⚠️ 외래 키가 있는 곳을 연관관계의 주인으로 정해라연관관계의 주인이란, 양방향 매핑에서 두 객체 중 외래 키를 누가 관리하는 객체를 말한다. 주인이 아닌 객체는 읽기만 가능하다. 즉, 연관관계의 주인은 단순히 외래 키를 누가 관리하느냐의 문제이기 때문에 비즈니스 상 우위에 있다고 주인으로 설정해서는 안된다. 이때, 일대다 관계에서 외래키는 항상 다(多)쪽에 위치하도록 설계해야 한다.만약, 위와 같은 연관관계가 존재한다고 가정해보자. 이때, Member(多)가 아닌 Team이 연관관계의 주인이 된다면 어떨까? 해당 팀에 소속된 member에 변경이 생기게 된다면 본인의 테이블인 Team이 아닌 다른 테이블 즉, Member 테이블에 Update 쿼리가 나가게 된다..
자바 ORM 표준 JPA 프로그래밍 - 섹션 3~4
·
JPA
섹션 3. 영속성 관리 - 내부 동작 방식엔티티의 생명주기비영속 (new/transient) : 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태영속 (managed) : 영속성 컨텍스트에 관리되는 상태준영속 (detached) : 영속성 컨텍스트에 저장되었다가 분리된 상태삭제 (removed) : 삭제된 상태영속성 컨텍스트영속성 컨텍스트란, 서버와 DB 중간에서 객체를 보관하는 세미 DB영속성 컨텍스트는 엔티티 매니저를 통해서 접근할 수 있으며 1차 캐시와 쓰기 지연 SQL 저장소가 존재한다.1차 캐시//엔티티를 생성한 상태(비영속)Member member = new Member();member.setId("member1");member.setUsername("회원1");//엔티티를 영속em.persis..