본문 바로가기

legacy/JPA

(30)
[JPA] Proxy와 연관관계, 지연로딩을 이용한 최적화 (new) 주문 Entity 주문 Entity가 가지고 있는 필드는 다음과 같습니다. 연관관계에 있는 Entity를 집중해 봅시다. 주문 Entity는 회원(Member), 주문 상픔(OrderItem), 배송 정보(Delivery) Entity와 연관관계에 있습니다. @Entity @Table(name = "orders") @Getter @Setter public class Order { @Id @GeneratedValue @Column(name = "order_id") private Long id; @ManyToOne @JoinColumn(name = "member_id") private Member member; @OneToMany(mappedBy = "order", cascade = CascadeType...
[JPA] 변경감지(Dirty Checking)과 병합(Merge) 영속성 컨텍스트에는 변경 감지(Dirty Checking)와 병합(Merge) 기능이 존재합니다. Entity의 필드값을 수정한다는 공통점이 있으나, 주의해야 할 차이점 또한 존재합니다. 이 글에서는 준영속 상태의 Entity에 접근하는 관점에서 설명합니다. 변경 감지(Dirty Checking) 변경 감지란 영속성 컨텍스트가 관리하는 영속 상태의 Entity의 필드 값을 수정합니다. (영속 상태라 함은 Entity가 식별자 값(ID)을 가지고 있음을 말합니다) 영속성 컨텍스트를 Flush하는 시점에 Entity와 SNAPSHOT을 비교하여 변경된 값을 추적합니다. 변경된 필드가 존재한다면 수정 쿼리를 작성하여 쓰기 지연 SQL 저장소에 보관하였다가 Flush 시점에 DB에 업데이트됩니다. 변경 감지..
[JPA] 비영속 엔티티 -> 영속 엔티티 변경 과정 (old1) EntityManager를 통해 비영속 상태의 Entity를 영속 상태의 Entity로 변경할 수 있습니다. 이때 사용되는 메서드는 merge()입니다. 그렇다면 비영속 -> 영속 상태로 변경하는 과정은 어떻게 될까요? 차근차근 알아봅시다. 준영속 상태 준영속 상태란 EntityManager가 관리하지 않는 Entity라고 생각하면 됩니다. 관리되지 않기 때문에 해당 엔티티의 값을 변경하더라도 DB에 반영되지가 않습니다. 준영속 상태의 특징은 다음과 같습니다. 비영속 상태에 가깝다 영속성 컨텍스트에 의해 관리되지 않으므로 1차 캐시, 쓰기 지연 SQL, 변경 감지 등을 지원하지 않습니다 식별자 값을 가지고 있다 준영속 상태가 되기 전에 영속 상태이었기 때문에 식별자 값을 가지고 있습니다. 이 식별자 값은..
[JPA] 준영속 상태 엔티티 -> 영속 상태 엔티티로 만들기, merge() (old2) 1. 비영속 상태의 엔티티 생성 영속성 컨텍스트(PersistContext)에 한 번도 저장된 적이 없는 Member를 생성합니다. EntityManager를 통해 persist를 하지 않았기 때문에 비영속 상태입니다. void test() { // member1 생성 Member member1 = new Member(); member1.setName("member1"); } 2. 비영속 상태 -> 영속 상태 EntityManager를 통해 Member를 persist하였습니다. 따라서 영속성 컨텍스트에 의해 관리되는 영속 상태의 엔티티가 됩니다. (DB에서 조회되지 않는다.) void test() { // member1 생성 Member member1 = new Member(); member1.setN..
[JPA-Error] IllegalArgumentException: Cannot create TypedQuery for query with more than one return using requested result type JPQL을 사용하여 Member 엔티티의 name과 age 필드를 조회하고 있었다. 코드는 다음과 같다. Query query = em.createQuery("select m.name, m.age from Member m", Member.class); List resultList = query.getResultList(); 위의 코드를 실행하면 다음과 같은 예외가 발생한다. 예외를 해석해보자면 TypeQuery를 생성할 수 없다는 듯하다. 난 분명 Query 객체를 생성했는데 왜 TypeQuery를 생성할 수 없다고 나오는 것인지 의문이었다. 역시나 컴파일러는 잘못이 없다. 내가 코드를 잘못 짜서 발생한 문제이다. Query 객체는 createQuery() 메서드에 반환타입의 정보를 넘겨줄 필요가 없다...
[JPA] 값 타입 공유문제 임베디드 값타입을 공유하는 두 객체가 있다. 한 객체에서 임베디드 값타입을 수정하면 이를 공유하는 다른 객체의 임베디드 값타임도 수정된다. 이는 자바에서 참조값을 수정하면 이를 참조하는 모든 객체의 값이 바뀌는 것과 동일한 원리이다. 근데 막상 임베디드 타입을 수정하니 한 객체에서만 수정되는 상황이 발생했다. 분명 공부할 때는 이를 공유하는 모든 객체의 임베디드 타입이 수정된다고 배웠는데 왜 한 객체만 수정되는 걸까? 그 이유는 ORM을 잘못 이해하고 사용했기 때문이었다. Member 엔티티 다른 필드들은 볼 필요없이 homeAddress 필드에만 집중하면 된다. @Entity public class Member { @Id @GeneratedValue @Column(name = "MEMBER_ID") p..
[JPA-Error] org.hibernate.TransientObjectException: object references an unsaved transient instance Embedded 값 타입을 다루고 있는데 오류가 발생했다. javax.persistence.RollbackException: Error while committing the transaction at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:81) at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:104) at jpay.jpastudy.JpastudyApplication.main(JpastudyApplication.java:44) Caused by: java.lang..
[JPA] 프록시 객체를 통해 필요한 엔티티만 조회하기, getReference() (old) DB에서 특정 엔티티를 조회하면 연관관계에 있는 엔티티 또한 같이 조회됩니다. 연관관계에 있는 엔티티도 조회하기 위해서는 DB에 join과 함께 쿼리문이 나가게 됩니다. 특정 상황에서는 굳이 연관관계에 있는 엔티티가 필요로 없는 상황이 있을 수도 있습니다. 이때 연관관계에 있는 엔티티까지 DB에서 조회하는 것은 효율적이지 않습니다. JPA는 이런 문제를 해결하기 위해 엔티티가 실제 사용될 때까지 DB에서 조회를 지연시키는 방법을 제공합니다. 이를 지연로딩이라고 합니다. 기존 조회 - 연관관계에 있는 엔티티까지 조회 EntityManager의 find() 메서드를 사용하여 엔티티를 조회합니다. clear()로 인해 영속성 컨텍스트가 초기화되었으므로 DB로부터 엔티티를 조회해서 1차 캐시에 저장합니다. 출력..