728x90
반응형
SMALL

JPA(Java Persistence API) 21

[JPA] OSIV (Open Session In View)

JPA를 사용할 때 "Open Session In View"라는 게 있다. 이 녀석이 은근 골치가 아픈 녀석인데 Spring Boot와 JPA를 같이 사용할 때 서버를 실행해 보면 (OSIV 관련 어떠한 작업도 하지 않았을 때) 이런 경고 문구가 노출된다. 2023-11-16T08:31:26.467+09:00 WARN 76673 --- [ restartedMain] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.op..

[JPA] 페치 조인의 한계와 한계 돌파

페치조인의 한계 JPA에서 정말 정말 중요한 페치 조인도 역시 만능은 아니고 컬렉션 데이터를 페치 조인할 때 페이징이 불가능하다. ToMany 관계를 페치 조인할 때라고 말하는 것과 동일한데, 결론은 페치 조인을 사용할 때 페이징이 불가능하다. 정확히 말하면 페이징이 불가능한것보단 하이버네이트가 메모리 상에서 페이징을 해주는데 이는 절대로 사용해선 안된다. 그냥 그러니까 ToMany 관계를 페치 조인할 땐 페이징이 불가능하다고 생각하면 된다. 그래서 이를 해결해야 하는데, 우선 다음과 같은 쿼리가 있다. public List findAllWithItem() { return em.createQuery("SELECT DISTINCT o " + "FROM Order o " + "JOIN FETCH o.memb..

[JPA] 변경감지와 Merge

데이터베이스에서 관리하고 있는 어떠한 데이터를 변경(수정)할 때 JPA는 어떻게 처리할까? JPA공부를 좀 해보니 영속성 컨텍스트에 관리되고 있는 엔티티는 트랜잭션이 커밋을 하는 시점 (다른 말로 영속성 컨텍스트가 닫히는 시점)에 flush()를 호출하고 그 때 변경된 내용이 있으면 변경 감지(dirty checking)를 통해 update 쿼리가 나간다. 그럼 영속성 컨텍스트가 더는 관리하지 않는 준영속 엔티티는 어떻게 변경할까? 방법은 두가지가 있다. - 영속성 컨텍스트가 다시 관리하게 한 후 변경 감지를 사용 - 병합(merge)를 사용 변경 감지 🟢 @Transactional void update(Item itemParam) { //itemParam: 파리미터로 넘어온 준영속 상태의 엔티티 Ite..

[JPA] Part 18. 벌크 연산

쿼리 한 번으로 여러 테이블 로우(레코드)를 변경하는 걸 말한다. UPDATE, DELETE 같은 것들이 이제 벌크 연산이 가능하다. 뭐 별건 아닌데 조금 주의할 사항이 있다. 벌크 연산은 영속성 컨텍스트를 무시하고 데이터베이스에 직접 쿼리한다. 이게 뭐가 문제냐면 벌크 연산을 처리한 전과 후에 만약 영속성 컨텍스트에 관리하고 있는 레코드(객체)가 있다면 벌크 연산이 적용되지 않은 채 영속성 컨텍스트에 그대로 관리될 수 있다. 그래서 이걸 해결하는 방법은 벌크 연산을 처리하고 영속성 컨텍스트를 초기화하는 것이다. 또는 영속성 컨텍스트에 뭔가를 관리하기 전 벌크 연산을 먼저 수행하는 것이다. 예를 들어보자. 멤버 3명이 있고 최초에 age를 0으로 설정했다. 그리고 영속성 컨텍스트에 멤버 3명을 영속시켰는..

[JPA] Part 17. Named Query

Named Query란, 문자열로만 이루어진 쿼리문에 이름을 부여해서 가져다가 사용할 수 있는 방식을 말하는데, 이게 굉장히 유용하다. 특히 Spring Data JPA와 같이 사용하게 된다면. 우선 Spring Data JPA가 없다고 가정했을 때 작성하는 방법은 @Entity 어노테이션이 있는 엔티티에 @NamedQuery 어노테이션을 사용하면 된다. @Entity @NamedQuery( name = "Member.findByUsername", query = "select m from Member m where m.username = :username") public class Member { ... } 이처럼 사용할 수 있고 이거를 가져다가 사용하는 쪽은 다음과 같이 사용하면 된다. List res..

[JPA] Part 16. Fetch JOIN (JPQL)

페치 조인은 JPQL에서 엄청 엄청 중요한 내용 중 하나라는 생각이 든다. 왜 그러냐면 이 페치 조인이 연관된 엔티티를 SQL 한 번에 다 가져올 수 있는 방법인데 이게 필요한 경우가 상당수 존재하며, 이 방식을 사용하지 않은 상태에서 지연 로딩을 걸고 필요할 때마다 가져오는 방식만을 사용한다면 가져와야 하는 연관 엔티티가 필요할 때마다 SQL이 계속 나가게 된다. 가장 쉬운 예시로 멤버를 조회할 때 멤버가 속한 팀까지 알아와야 하는 경우에 페치 조인을 사용하지 않고 지연 로딩인 상태에서 멤버 100명을 조회하면 멤버 100명을 조회하는 쿼리 한 번이 우선 나가게 된다. 여기서 팀은 같이 조회되지 않는다 지연 로딩이기 때문에. 그리고 실제 멤버의 팀을 호출하는 순간에 팀을 알아오는 SQL이 나가는데 멤버..

[JPA] Part 15. JPQL

JPQL(Java Persistence Query Language)는 데이터베이스의 SQL과 유사하나 객체지향 쿼리 언어이며 그렇기에 테이블을 대상으로 쿼리하는 게 아니라 엔티티 객체를 대상으로 쿼리한다는 차이점이 있다. JPQL은 SQL을 추상화해서 특정 데이터베이스 SQL에 의존하지 않는다. 이 말은 데이터베이스마다 다른 방언(MySQL은 LIMIT, Oracle은 ROWNUM 같은)에 상관없이 동작한다는 의미이다. 그러나 결국, DB는 SQL만을 받기 때문에 JPQL은 결국에는 SQL로 변환된다. 이 JPQL을 잘 이해하고 사용할 줄 알아야 기본적인 쿼리문을 사용하는데 문제가 없고 복잡한 쿼리를 처리해주는 QueryDSL도 편하게 사용할 수 있다. 그래서 JPQL을 잘 사용할 줄 알아야하는 것 같다..

[JPA] Part 14. 컬렉션 값 타입

엔티티에 컬렉션으로 관리하는 데이터는 흔히 있을 수 있는 일이지만 DB는 기본적으로는 컬렉션 데이터를 지원하지 않는다. 물론 요즘은 여러 방법으로 컬렉션을 테이블에서 관리할 수 있지만(JSON으로 데이터를 저장한다든지 등) 그러나 정석적인 방법은 컬렉션 데이터를 테이블 화해서 참조로 관리하는 것이다. 아래 그림을 보자. 멤버라는 엔티티가 관리하는 데이터 favoriteFoods와 addressHistory는 컬렉션 값 타입이다. 이런 엔티티를 테이블화 하기 위해서는 각 컬렉션 값 타입을 테이블로 분리해서 1:N 관계로 만드는 것이다. 이게 정석적인 방법이다. 위 그림을 보면 Address도 FavoriteFood도 모든 필드가 하나의 PK인데 이 이유는 컬렉션 '값 타입'이기 때문이다. 값 타입은 하나의..

[JPA] Part 13. 임베디드 타입

임베디드 타입은 꽤나 사용성을 높여준다. 임베디드 타입은 무엇이냐면 특정 엔티티에 필요한 필드를 클래스타입으로 받는 경우이다. 아래 예를 보자. 좌측 테이블은 기본타입으로만 설정된 테이블이다. 물론 이게 잘못된 건 아니다. 근데 기본 타입이 아니고 클래스로 설계된 타입을 사용할 때 얻는 이점이 매우 많기 때문에 이를 우측 테이블인 임베디드형 테이블로 변환할 수 있다. 임베디드 타입을 사용시 어떤 이점이 있을까? 재사용성 높은 응집도 의미 있는 메서드를 만들어 사용할 수 있고 그에 따라 객체 지향형 설계가 가능해짐 예) Period.isWork()와 같은 메서드를 만들어서 해당 객체에서만 사용되는 메서드를 Period 클래스에서 구현 가능 임베디드 타입을 포함한 모든 값 타입은, 값 타입을 소유한 엔티티에..

[JPA] Part 12. CASCADE

CASCADE는 영속성 전이를 어떤식으로 동작시킬 거냐를 지정하는 옵션이다. 일단 가장 먼저 말할거는 이 CASCADE는 연관관계나 지연로딩 즉시로딩과 전혀 아무런 상관이 없다. 그저 특정 엔티티를 영속 상태로 만들 때 연관된 엔티티를 어떻게 할건지를 지정한다. 예를 들면 부모를 저장할 때 부모에 연관된 자식도 같이 저장하는 경우를 말한다. 그러니까 CASCADE는 부모 엔티티에서만 설정한다고 봐도 사실 무방하다고 본다. 말로는 잘 이해가 안되고 코드로 보면 바로 이해가 된다. Parent Class package org.example.entity.cascade; import javax.persistence.*; import java.util.ArrayList; import java.util.List; ..

728x90
반응형
LIST