본문 바로가기
개발자 일지/JPA

[인프런 JPA]자바 ORM 표준 JPA 프로그래밍 정리2

by 네빌링 2023. 1. 31.
반응형

-인프런 김영한님 JPA 강의를 듣고 정리한다.
-값타입과 객체지향쿼리언어(JPQL) 파트를 정리한다.
-이미지 출처는 인프런 강의 자료를 참고하였다.
-가물가물한 상태에서 재정리하고 있는 상태라서 중간중간 틀린 개념이나 어설픈 설명이 많을 수 있다.


9.값 타입

1.기본 값 타입
 
JPA의 데이터타입 분류는 크게 엔티티 타입, 값 타입이 있다.
 

  • 엔티티 타입
    • @Entity로 정의하는 객체
    • 데이터가 변해도 식별자로 지속 추적 가능
  • 값 타입
    • 1)기본값타입
      • 자바기본타입(int, double) : 생명주기를 엔티티 수명에 의존 / 공유하면 안 됨 / 기본타입은 항상 값을 복사
      • 래퍼 크래스(Integer, Long) : 클래스라 공유가 되지만 변경 안 됨(사이드이팩트 방지)
    • 2)임베디드 타입(embedded type, 복합값타입) : 새로운 값 타입 직접 정의 / JPA는 임베디드 타입이라 함 / x,y좌표 포지션 클래스같은 예
    • 3)컬렉션 값 타입(collection value type)

 

 
 
2.임베디드 타입
 
int와 double처럼 공유가 불가능하고 엔티티에 의존적이다. 값 타입이기 때문에 생명주기를 엔티티에 의존한다.
 
Member엔티티가 주소(Address), 근무기간(Period)의 임베디드 타입을 사용한다면 Address, Period에는 @Embeddable을 붙여주고 쓰는 곳에는 @Embedded를 아래와 같이 붙여준다.
 

 
그 밖에 다음과 같은 특징이 있다.

  • 임베디드 타입을 사용하기 전과 후의 매핑 테이블은 같음
  • 잘 설계한 ORM 애플리케이션은 매핑한 테이블 수보다 클래스 수가 더 많음
  • 임베디드 타입은 임베디드 타입, 엔티티 타입 모두 가질 수 있음
  • 같은 임베디드 타입이 2개 있으면 @AttributeOverrides, @AttributeOveride 속성을 재정의 해야 함
  • 임베디드 타입값이 null이면 내부 필드도 null

 
3.값 타입의 불변 객체
 
임베디드 타입같은 값 타입을 여러 엔티티에서 공유하면 사이드 이팩트가 발생할 수 있다.
 

address 변수를 공유하여 member2의 주소가 의도치 않게 변경 됨

 
 
 
임베디드 타입은 객체 타입이기 때문에 참조값이 복사 될 수 있다. 그래서 객체의 공유참조를 막기 위해 불변객체(immutable object)로 설계해야 한다.
 

  • 불변객체는 생성시점 이후 값을 변경할 수 없는 객체를 의미
  • 생성자로만 값을 설정하고 수정자를 만들지 않음
  • Integer, String은 자바가 제공하는 대표적 불변 객체 

 
4.값 타입의 비교
 
값 타입은 equals()를 사용하여 동등성(equivalence) 비교를 해야한다. 

  • 동일성(Identity) 비교 : 값 타입의 참조값을 비교(==)
  • 동등성(Equivalence) 비교 : 값 타입의 인스턴스 값을 비교(equals)

 
Address 같은 임베디드 타입의 경우 equals를 재정의해준다. 아래와 같이 정의해준다.
 

 
5.값 타입 컬렉션
 
데이터베이스는 컬렉션 션을 같은 테이블에 저장할 수 없기 때문에 1:N으로 풀어서 별도 테이블을 만들어야 한다. 그래서 값 타입을 하나 이상 저장할 때 @ElementCollection, @CollectionTable 어노테이션을 사용한다.
 

 
다음과 같이 테스트 한다.
 

컬렉션 타입에 데이터를 담기

 

 
그 밖에 값타입과 관련된 내용은 다음과 같다.

  • 엔티티에 의존하고 엔티티가 아니기 때문에 persist 처리같은 것들이 필요 없음
  • 영속성전이, 고아객체 제거 기능을 필수로 갖는다고 보면 됨(cascade, OrphanType=true)
  • 값 타입 컬렉션도 지연 로딩 전략(fetch = FetchType.LAZY)
  • 값 타입 컬렉션은 다음과 같은 제약 사항이 존재
    • 1)값 타입은 엔티티와 다르게 식별자 개념이 없음
    • 2)값을 변경시 추적 어려움
    • 3)값 타입 컬렉션에 변경 사항이 발생하면 주인 엔티티와 연관된 모든 데이터 삭제하고 값 타입컬렉션에 있는 현재값을 모두 다시 저장함
  • 값 타입 컬렉션 대안
    • 실무에서는 값타입컬렉션 대신 1:N 고려
    • AddressEnttiy로 래핑을 해서 하면 테이블에 id가 생기고 맘대로 update가 가능
    • 값 타입은 진짜 단순한 상황에서 사용

 

엔티티값타입
식별자 있음식별자 없음
생명주기 관리생명주기를 엔티티에 의존
공유 가능공유하지 않는 것이 안전(복사기능사용)  /불변객체 사용 권장

 
 

10.객체지향 쿼리 언어1 - 기본 문법

 
1.소개
 
JPA는 다양항 쿼리 방법을 지원한다.

  • JPQL : 표준문법
  • JPA Criteria
  • QueryDSL
  • 네이티브 SQL : 표준 SQL 문법을 벗어나는 쿼리를 써야하는 경우(쌩쿼리)
  • JDBC API 직접 사용, MyBatis랑 함께 사용

JPQL은 단순하게 em.find()등으로 조회하기 어려운 상황에서 사용한다. 예를 들어 나이가 15세 이상인 회원을 모두 검색하고 싶거나 회원탈퇴한 회원만 찾고싶은 경우 등의 상황에서 사용한다. SQL을 추상화한 JPQL이라는 객체지향쿼리언어를 사용하며 SQL과 문법은 유사하고 JPQL은 엔티티 객체를 대상으로 쿼리를 날린다
 
JPA Criteria는 문자가 아닌 자바코드로 JPQL을 작성한다. JPQL 빌더역할을 하고 JPA공식스펙이지만 실용성이 없고 복잡하기 때문에 QueryDSL을 사용 권장한다.
 
QueryDSL은 문자가 아닌 자바코드로 JPQL을 작성할 수 있으며 JPQL 빌더역할을 하며 컴파일시점 문법오류 캐치가 가능하다. 동적쿼리 작성이 편리하고 단순하여 실무사용에 권장된다.
 
네이티브 SQL은 JPA가 제공하는 SQL을 직접 사용하는 기능으로 JPQL로 해결할 수 없는 특정 데이터베이스에 의존적인 기능이다.(오라클 Connect by 등)
 
2.기본 문법과 쿼리 API
 
문법적으로 엔티티 별칭은 필수며 as는 생략 가능하다. JPQL 쿼리 반환타입은 기본적으로 TypeQuery, Query를 사용할 수 있는데 TypeQuery는 반환타입이 명확한 경우 사용하고 Query는 반환타입이 명확하지 않을 때 사용한다.
 

 

  • 결과조회 API
    • 1)query.getResultList() : 결과가 하나 이상일 때 리스트 반환(결과 없으면 빈 리스트 반환)
    • 2)query.getSingleResult() : 결과가 정확히 하나, 단일 객체 반환
      • 결과 없으면 : javax.persistence.NoResultException
      • 결과 둘 이상이면 : javax.persistence.NonUniqueResultException

 
3.프로젝션
 
SELECT 절에 조회할 대상을 지정하는 것을 의미한다.
 

  • select m FROM Member m -> 엔티티 프로젝션
  • select m.team FROM Member m -> 엔티티 프로젝션
  • select m.address Member m -> 임베디드 타입 프로젝션
  • select m.username, m.age FROM Member m -> 스칼라 타입 프로젝션
  • distinct로 중복 제거

엔티티 프로젝션 후 값을 변겨하면(ex : setAge(20))하면 업데이트 된다. 다음과 같이 확인할 수 있다.
 

엔티티 프로젝션

 

엔티티 안 엔티티 프로젝션

 
스칼라 타입 프로젝션시에는 다음과 같이 Object[] 타입으로 조회 가능하다.

 
new 명령어로 조회할 수도 있다.
 

 
 
4.페이징
 
JPA는 페이징을 다음 두 API로 추상화했다.

  • setFirstResult(int startPosition) : 조회 시작 위치
  • setMaxResults(int maxResult) : 조회할 데이터 수

 

 
 
 
5.조인
 

  • 내부조인 : SELECT m FROM Member m [INNER] JOIN m.teat t
  • 외부조인 : SELECT m FROM Member m LEFT [OUTER] JOIN m.team t
  • 세타조인 : SELECT count(m) from Member m, Team t where m.username = t.name

 
ON절은 JPA 2.1부터 지원한다.
 

 
6.서브쿼리
 

JPA 서브쿼리는 일부 한계가 있는데 FROM절에서는 서브쿼리를 현재 JPQL에서 사용할 수 없다. 조인으로 풀 수 있으면 조인으로 해결한다.
 
 
 
7.JPQL 타입 표현과 기타식
 
JPQL 타입표현은 다음과 같다.

  • 문자 : 'HELLO'
  • 숫자 : 10L, 10D
  • ENUM : 풀패키지명으로 가져와야함(아래 참고)

 

ENUM은 풀패키지명으로 가져온다.

 
Item을 상속한 Book만 가져오고 싶으면 아래처럼 타입캐스팅을 한다.

  • 엔티티 타입 : TYPE(m) = MEMBER(상속관계에서 사용)

 
 
 
 
 
8.조건식(CASE 등)
 

김영한님 참고자료 일부

 
9.JPQL 함수

 
JPQL 기본 함수(JPQL이 제공하는 표준 함수)는 다음과 같은 것들이 있다.
  • CONCAT, SUBSTRING, TRIM, LOWER, LENGTH, ABS, SQRT, MOD, SIZE, INDEX(JPA용도) ....
DB종속적인 함수를 사용하기 위해서는 하이버네이트 기준으로 방언을 추가해야한다. 사용하는 DB방언을 상속받고 사용자 정의함수를 등록한다.
 
select function('group_concat', i.name) from Item i
 
사용자 정의 함수 호출을 위한 방언 등록

 
 

11.객체지향 쿼리 언어2 - 중급 문법

 
1.경로 표현식
2.페치 조인1 - 기본
3.페치 조인2 - 한계
4.JPQL - 다형성 쿼리
5.엔티티 직접 사용
6.Named 쿼리
7.벌크 연산
 

반응형