JPA Entity 설계를 하면서 꼭 겪는 문제
바로 내가 원하지 않는 쿼리가 같이 날라가는 문제!
그런 문제들은 꼭 공부를 해봐야 겠죠!
Entity에서 find 문을 실행하면
orderRepository.findById(id)
이런식으로 select와 함께 update가 같이 날라갑니다!
이게 저번 포스팅때 이야기한 Dirty Checking과 관련이 있을까요?
JPA를 사용하면 대부분 Hibernate를 사용할텐데한 트랜젝션 범위에서 Entity를 조회하면 조회 시점의 Entity 복사본을 만듭니다
Entity 원본과 복사본의 비교는 객체의 equals로 판단하지 않고 각 컬럼들이 같은지 비교를 한다.
how-does-hibernate-detect-dirty-state-of-an-entity-object
각 컬럼들의 비교는 Objects.equals로 진행한다.
Hibernate 5.2 까지는 Hibernate의 EqualsHelper.equals로 비교하였습니다. Hibernate Issue
칼럼 하나 비교에 사용되는 이 함수는 해당 객체의 equals 메소드를 호출한다.
Java에서는 객체의 equals를 override하지 않으면 레퍼런스(주소) 비교를 합니다.
같은 값을 가져도 신규 생성된 객체와 기존 객체와 비교하면 false가 발생합니다
클래스에 @EqualsAndHashCode를 달아준다 = equals를 override 한다.
-> Dirty Checking이 발생하지 않는다.
@Embedded 로 선언된 객체는 필드가 아닌 Entity의 영역을 확대시킨 것이라, 실제 비교를 @Embedded로 선언된 객체가 아닌 @Embedded 클래스 내부의 필드들이 대상입니다.
equals
를 사용하지 않고 필드값에 대해 각각 equals
를 사용합니다.Period 의 경우 객체형 필드이지만
불변 객체(Immutable type)라서 이미 equals가 구현되어 있다.
복사본이 생겨도 동일한 객체가 생성돼서 Dirty Checking하지 않는다.
LocalDateTime, LocalTime 역시 동일한 객체가 생성되지 않으므로 DirtyChecking 대상이 아니다.
@OneToMany
, @OneToOne
, @ManyToOne
등으로 선언된 객체. Entity이기 때문에 필드 비교 대상이 아니다.