jpa, spring-data-jpa 시작하기, 메서드 구현
Spring-data-jpa 란? spring-data-jpa 는 스프링을 아주 편리하게 사용하도록 도와주는 라이브러리이다. 반복되는 공통 매서드를 미리 구현했다. spring-data의 인터페이스를 상속한다.
Spring-data-jpa 란? spring-data-jpa 는 스프링을 아주 편리하게 사용하도록 도와주는 라이브러리이다. 반복되는 공통 매서드를 미리 구현했다. spring-data의 인터페이스를 상속한다.
들어가며 이전 블로그는 xToMany 를 출력할 때 entity 를 값으로 하였다. 지금 블로그는 dto로 반환하는 방식을 정리한다.
들어가며 xToOne 연관관계에 이어 xToMany 연관관계에서의 조회에 대한 최적화 방식을 정리한다. xToOne은 관계형데이타베이스의 입장에서 다의 입장을 가지며, 이는 한방 쿼리와 페이징 처리가 수월하다. xToMany는 일의 입장을 가지며, join을 수행할 경우 데이터 뻥튀기의 문제가 발생한다. 이로 인하여, 페이징 처리가 어렵다. 페이징은 다의 입장에서 수행되기 때문이다. 한 방 쿼리가 사실상 불가능하다. 다의 입장에서 레코드를 출력하면 일의 데이터가 다의 칼럼에 중복되어 출력된다. 깔끔하게 떨어지는 쿼리를 만들기 어렵다.
들어가며 스프링을 기반으로 api 프로젝트를 생성한다. jpa로 데이터를 통제한다. api의 경우 json 형태로 데이터를 응답한다. rest api 에서 스펙을 유지한 채, 효과적으로 엔티티 객체를 조작하는 방식을 정리한다. xToOne과 xToMany를 분리하여 정리한다. 영속성 컨텍스트에서 엔티티를 리턴하여 dto로 변환하는 방식과 처음부터 dto 자체를 출력하는 방식으로 분리하여 정리한다.
Open Session in view 영속성 컨텍스트를 view 단까지 유지함을 의미한다. 그러니까 Trnasaction로 명시한 위치를 넘어서 controller 나 심지어 view template 까지 영속성 컨텍스트를 사용한다. session 이란 현재 jpa를 의미한다. 하이버네이트에서 나온 기술이라서 jpa 가 아닌 session 단어를 사용한다. 기본 값은 true 이다.
7일까지의 통계를 매일마다 분석하기 https://leetcode.com/problems/restaurant-growth/ Customer 테이블이 있다. 매일마다 해당일을 기준으로 7일 전까지의 통계를 내고 싶다. 원하는 통계 값은 총 판매량과 그것을 7로 나눈 평균값이다.
준영속 객체의 update를 위하여 영속성 컨텍스트에서 관리를 하기 위해서는 특정 객체게 엔티티 매니저에 영속성으로 들어가도록 하거나(em.persist(obj)), 영속성 컨텍스트로 객체를 찾아오면 된다(em.find(Member.class, 1L)). 만약 DB에서의 아이디(@Id)의 값을 알고, 그 값을 객체로 생성하였고, 이를 update 하려면 어떻게 해야할까? 여기서 논의할 방법은 두 가지이다. merge병함과 dirty checking 더티 체킹이다.
테스트의 DB는? 테스트를 진행할 때 DB와 통신이 필요한 경우가 많다. 스프링부트는 어플리케이션 내부에서 가상의 DB인 in-memory-db를 지원한다. 통합 테스트를 편리하게 수행하도록 도와준다. 그 중 h2를 살펴본다.
스프링과 JPA 스프링이 다른 라이브러리를 쉽게 개발하도록 보조하듯, JPA 역시 상당 부분 자동 세팅을 한다.
경로 표현식과 묵시적 조인 .을 찍어 객체 그래프를 탐색하기
fetch join jpa 성능 최적화를 위한 매우 중요한 기능. sql 기본 문법에는 없는, jpa의 조인 기법. 연관된 엔티티와 컬렉션을 한 번에 조회할 수 있음. 즉시 로딩과 유사. 객체 그래프 전체를 한 번에 가져온다. 다만, fetch join을 명시하여 한방 쿼리를 날리는 순간을 정할 수 있다는 점이 즉시로딩과의 차이. OneToMany를 기준으로 객체를 출력할 때 중복 문제가 발생. distinct 를 사용해야 한다. 대부분의 n+1의 문제를 해소한다. (lazy 로딩으로 인한 프록시 셀렉으로부터)
동일성과 동등성 자바에서의 동일성이란 완전하게 같음을 의미한다. 변수에 할당된 값이 일치해야 한다. 동일성 비교는 == 을 사용한다. 기본타입의 경우 값을 비교한다. 값이 같으면 true를 반환한다. 참조변수는 주소가 같은 위치를 가리킴을 의미한다. 동등성은 동일성보다 넓은 개념이다. 주소가 같지 않더라도 값이 동일할 경우 동등하다고 본다. equals 메서드를 사용한다. Object 클래스는 equals를 기본적으로 동일성 비교한다. 다만 equals는 재정의 가능하다. equals와 hashcode를 재정의한 클래스는 동일성을 false로 반환하더라도 동등성을 true로 반환할 수 있다. String은 객체지만 특별하다. 동등한 객체는 동시에 동일한 객체이다. 같은 문자열을 가진 String은 equals와 == 모두 true를 반환한다. 다만 new String() 을 사용할 경우 더 이상 동일성을 보장받지 못환다. 방어적으로 equals 메서드를 사용하는...
JPQL 이란? 객체지향 쿼리. 테이블이 아닌 객체를 대상으로 하는 SQL.
JPQL 테이블이 아닌 객체를 대상으로 검색하는 객체 지향 SQL. 단순한 persist 로 해결할 수 없는 복잡한 쿼리를, 직접 SQL을 작성하여 구현. 표준 SQL을 따르며 관련한 문법을 지원. DB마다의 방언으로 자동 번역. JPA의 잘 활용하기 위한 가장 기본적인 기술.
상속관계의 구현 객체에서의 상속과 같은 개념은 관계형 데이터베이스에 존재하지 않는다. 다만, 슈퍼 테이블 개념이 있지만, 이것은 상속관계를 구현하는 방법 중 하나로 사용된다. 논리 모델을 구현 모델(DB설계)로 구현한다. 반대로 객체 입장에서의 설계는 동일(논리모델)하지만 그것의 구현만 차이를 가진다. JPA나 자바 입장에서는 반대로 모든 방식을 지원한다.
프록시와 엔티티 객체의 조회 em.find() : db로 조회한다. em.reference() : db를 사용하지 않고 객체를 조회한다. 정확하게 프록시 엔티티 객체를 조회한다.
mappedSuperclass 공통 맵핑 regId, regDt 등 모든 객체(테이블)의 공통 정보가 존재함. 이러한 공통 정보를 하나의 엔티티로 묶음. MappedSuperclass 를 어너테이션으로 한다. 단독으로 사용할 일이 없으므로 추상 클래스(abstract class)로 한다. 매우 자주 사용한다.
즉시로딩과 지연로딩 JPA나 그것의 구현체는 기본적으로 즉시로딩을 이상적으로 본다. 그러니까 해당 엔티티의 연관관계를 가진 객체가 채워진 형태를 이상적으로 본다. 하지만 이 경우 n+1의 문제나 불필요한 데이터의 호출 등을 만들기 때문에, 실무에서는 무조건 지연로딩을 사용한다. 즉시로딩의 장점인 데이터의 일괄 호출로 인한 효율은 fetch 나 기타 기법으로 해소 가능하다. 지연로딩은 프록시 기법을 사용하기 때문에 앞서 정리한 jpa 와 프록시와 관련한 블로그를 참고 바란다.
jpa를 기준으로 본 데이터 타입 jpa를 기준으로 데이터 타입은 엔티티와 엔티티 아닌 것으로 구분한다.
영속성을 한 번에 관리한다. 영속성 전이 cascade 기본적으로 영속성은 아래와 같이 관리한다.
양방향과 단방향 JPA는 여러가지의 연관관계를 지원한다. 다대일, 일대다, 일대일, 다대일. 사실상 일대다와 일대일 연관관계만 사용한다. 일대다는 아주 가끔 쓰고 다대다는 사용하지 않는다. 연관관계는 기본적으로 단방향만 있다. 그러므로 다대일과 일대다는 다르다. 다대일 단방향과 다대일 양방향이 있다. 다대일, 일대다 일대다, 다대일은 이전의 블로그에 정리하였으므로 생략한다. 대체로 다대일을 사용한다. 정확하게는 외래키를 가진 쪽을 주인으로 하는 방식을 선택한다. 이래야지 jpa가 sql을 생성할 때 직관적이다.
DB와 객체지향 개발과의 차이, 외래키와 참조 객체형 데이타베이스에서 연관된 레코드를 검색할 때 외래 키로 조회한다. 객체지향적 프로그래밍에서 객체는 참조를 통해 조회한다. 두 개의 간격을 해소해야 한다. 필드에 외래키를 가지는 Long teamId 형태의 데이타 중심의 개발로부터, Team team으로의 객체 지향적 개발로 전환한다. 이러한 격차의 해소가 JPA의 중요한 문제 중 하나이다.
@Entity 와 생성 규칙 Entity가 붙은 클래스는 JPA가 관리한다. 리플렉션 등 기술을 사용하기 때문에 기본 생성자가 필수이다. final, enum, interface 등 사용할 수 없다. 엔티티의 데이타베이스를 위한 설정값(not null, unique 등) 이 반드시 자바 객체로서의 상태와 일치하는 것은 아니다.
관계형 데이타베이스의 헤게모니 DB의 경우 관계형 데이타베이스가 대세이다. 자바를 통해서는 객체지향적 개발을 지향하지만, DB와의 패러다임 불일치 문제로 인한 문제가 계속 발생한다.
영속성 컨텍스트란? 영속성 컨텍스트는 1차 캐시라고 하며, DB와 객체 사이의 중간 단계이다. 엔티티 매니저를 통해 영속성 컨텍스트에 접근한다. 자바 환경에서는 EntityManager 와 persistance context 는 1:1 관계이며, EntityManager에 종속된다. 영속성 컨텍스트를 통해 다양한 장점을 가진다.
들어가며 가장 기본적인 형태의 JPA의 활용은 아래와 같다. SQL을 사용하여 쿼리를 할 수 있으며 이를 JPQL이라 한다. JPQ를 통하여 쿼리를 날려도, 객체지향적 개발이 가능하고 다양한 메서드를 사용하며 방언에 자유롭기 때문에 활용도가 아주 높다.
join 과 집계 함수 inner join 의 경우 두 개의 테이블을 특정 기준으로 비교하여 두 테이블에 레코드가 모두 존재하는 경우만 출력한다. outer join 의 경우 기준이 되는 테이블 전체의 출력을 보장한다. left join을 할 경우 왼쪽 테이블 전체의 출력을 보장한다. 왼쪽 테이블의 어떤 레코드가 오른쪽의 레코드와 연결되는 값이 없으면 오른쪽 레코드가 들어갈 칼럼에 null을 채운다. null의 존재유무가 테이블 간 비교를 위한 중요한 기준이 된다. 하지만 레코드를 reduce하는 sum 등의 집계함수는 null 등을 어떻게 처리해야 하는가?
join과 데이터의 뻥튀기 아래에는 두 개의 테이블이 있다. 과일과 주문이다. 과일에는 상품고유번호(goods_id)와 농장고유번호(farm_id)로 있다. 주문에는 주문고유번호(order_id)가 추가된다.
sql의 데이터 타입 sql에는 다양한 데이터 타입이 있다. (사족이지만) varchar와 char의 차이가 인상적이다. varchar는 초기값이 얼마로 정해졌든, 실제 레코드가 들어갈 때의 점유 공간은 실제 입력되는 값의 길이에 따른다. 하지만 char의 경우 레코드가 생성될 때 무조건 그것이 초기값만큼 점유한다. 문자열 이외에 int, date, datetime 등 다양한 데이터 타입이 있다. 더 나아가 인텔리제이는 IDE 차원에서의 보정 기능이 있다. boolean 등을 지원하고 0과 1을 true와 false로 변환해주는 등 편리한 기능을 제공한다. 이번에는 date 타입에 대하여 다루고자 한다.
반복문과 단항연산자 자바를 다루면 매일 사용하는 반복문의 인자는 선언 및 초기화, 반복의 조건, 단항연산자로 이뤄져 있다.