JPQL 중급 문법

반응형
반응형

이제 마지막이다.!

최근 부터 제목 짓는게 어려워서 그냥 목차를 사용하고 있다.

경로 표현식

이것을 이해 하기 위해 잠시 sql을 작성해보자.

select * from A;

대충 이런 sql이 존재한다고 가정하자.
이것을 JPQL로 바꾼다면

select m from A m

이런식으로 수정할 수 있다.
여기서 m이 경로 표현식이다.
m은 * 즉 와일드 카드로 대체가 되어진다. 그 말은 이것은 엔티티라는 뜻이 된다.
그럼 결국은 m다음에 나올 수 있는 값들이 어떤것이 있을까?

엔티티는 다음으로 준비하였다.

@Id @GeneratedValue
private Long id;

private String server;
private String name;
@OneToMany(mappedBy = "school", fetch = FetchType.LAZY)
private List<Student> students = new ArrayList<>();

1. 그냥 값

이것은 말그대로 엔티티의 값을 뜻하게 된다. 
여기에서는 id, server,name을 뜻하게 된다.
당연한 말이지만 이 다음으로 검색은 불가능하다.

왜냐하면 이것은 값이기 때문에 당연한 결과라 생각이 든다.

2. 값 타입
아쉽게도? 이 예제에서는 값 타입이 존재하지 않는다.
대충 address라고 추가한뒤 다시 말해보면

이거는 검색이 계속 된다는 것을 알 수 있다.
당연한 말이겠지만 값 타입을 계속 만들면 경로 표현식을 계속 샇을 수 있을 것 같다.

3. 1:다 관계

이거는 students를 뜻한다. 이것도 어떻게 보면 검색이 가능할 거라 예상하는데
아쉽게도? 검색이 불가하다. 뇌피셜을 작성해보자면
students는 여러개인데 하나를 확정지어서 말할 수 없기 때문이라 생각이 든다.

경로 표현식이 select다음에 나오는게 아니다.join등에 나올 수 있다는 걸로 알고 있다.
경로만 작성할 수 있는 곳에 작성할 수 있지 않을까?

페치 조인

JPA를 공부하면서 모든 연관관계의 fetch를 LAZY로 바꿔야 한다.
LAZY라는 의미는 뭔가 늦는다라는 의미를 내포 하고 있다.
그러니까 db를 바로 거치지 않고 프록시를 거친다라고 할 수 있다.
그렇게 되면 자연스럽게 N + 1문제가 해결이 된다.
여기에 대해서는 조금더 공부를 해야 되겠지만 아무튼 지금 알고 있는 것을 토대로 설명하자면
LAZY를 하게 되면 단점이 EAGER로 하게 되면 자동으로? 조인이 걸린것과 달리
LAZY는 조인이 걸리지 않고 원하는 부분만 나온다는 것이 특징이라고 할 수 있다.

근데 문제는 그 일부분만 가져오고 싶으면 큰 문제가 되지 않겠지만, 
어떨때는 join을 걸고 싶을 수도 있다.
여기서 문제가 발생하는데
JOIN을 걸게 되면 다시 N+1문제가 발생이 발생할 수 있는 걸로 알고 있다.
이부분은 확실하지 않기 때문에 작성만 하고 넘어갈 예정

아무튼 이것을 방지하는 방법으로 fetch join이라는 것을 만들 수 있다.

select m from Student m join fetch School s

이렇게 만들게 되면 N+1문제를 해결할 수 있다고 한다.
fetch join에 대한 문제도 있긴하지만 기억이 나지 않는 관계로 작성하지 않는다.
JPQL쪽은 다시 한번더 공부를 해야 할 것 같다. 

아무튼 웬만한 N+1문제는 fetch join을 활용하면 해결이 된다고 한다.

Named query

이거는 생각보다 신기한 방법이었다.
엔티티에 직접 쿼리를 작성해서 런타임 시점에 이것을 사용하게 하면 된다고 한다.

@NamedQuery(
    name = "School.selectSever",
    query = "select s.server from School s where s.server =:serverName"
)

요런식으로 설정하면 된다는데 지금 보니까 s.server여기에도 경로 표현식이 들어간다는 것을 알 수 있다.
참고로 name은 엔티티를 작성하지 않고 메서드만 작성해도 되기는 한다고 한다. 
저거는 단순히 관행정도로 알고 있다.

사용하는 방법은 다음과 같다.

List<School> serverName = em.createNamedQuery("School.selectSever", School.class)
                            .getResultList();

근데 솔직히 엔티티에 이렇게 작성하는 건 조금 지저분해 보인다.
그래서 spring jpa data에서 조금더 깔끔하게? 하는 방법을 제공한다고 한다.

벌크 연산

때로는 하나만 수정하는 것이 아니라 여러개를 동시에 수정을 해야하는 경우도 종종 있다.
그래서 나온것이 벌크 연산이다.

사용하는 방법은 단순하다.

 int result = em.createQuery("update Student s set s.name = 'hello' ")
                     .executeUpdate();

요런식으로 수정하면 되는데
문제는 이거는 db에 바로 접근하는 방법이라는 점이다.
그래서 특정 엔티티를 검색해서 찾으려 한다면? 뭐가 나올까?
hello라는 값이 나올까 아니면 다른 값이 나올까?

Student student = em.find(Student.class, 1);
System.out.println(student.getName());

어라 왜 hello가 나오지 패치 했나?
아무튼 원래 안되서 
초기화 시켜야 되는 걸로 알고 있는데 왜 바뀌지? 이거는 나중에 생각하기로 하고 넘어가자.
왜냐하면 벌크 연산은 영속화가 되지 않기 때문에 em.clear()를 해줘야 된다.

여기까지 JPA학습을 하엿다.
긴 시간이었지만 생각보다 알찬 경험이라 여겨진다.
여기에 작성하지 않은 것들도 생각보다 많지만 이거는 어디까지나 얼마나 기억하고 있는지 체크하는 거라..
조금더 보강하면 더 잘 사용할 수 있을 것 같다.

반응형

'JPA' 카테고리의 다른 글

JPA 스터디 3주차  (0) 2022.01.26
JPA 스터디 2주차  (0) 2022.01.20
JPQL 기본 문법  (0) 2021.12.18
값 타입 작성 방법  (0) 2021.12.12
Proxy?  (0) 2021.12.04

댓글

Designed by JB FACTORY