inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

Hibernate Proxy객체가 실제객체로 변환이 안돼요

39

papakang22

작성한 질문수 2

0

먼저 Entity Code부터 보여드리겠습니다.

 

FieldGroupMapping(부모)


@Entity
@Table(name = "FIELD_GROUP_MAPPING")
@Getter
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class FieldGroupMapping extends CreationAuditingEntity {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "FIELD_GRP_MPPG_ID", nullable = false)
  private Long id;

  @Column(name = "FIELD_CD", length = 50, nullable = false)
  private String fieldCd;

  @ManyToOne(fetch = FetchType.EAGER, optional = false)
  @JoinColumn(name = "FIELD_CD",
      referencedColumnName = "FIELD_CD",
      insertable = false,
      updatable = false,
      foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
  private FieldMetadata field;
}

 

FieldMetadata (자식)


@Entity
@Table(name = "FIELD_METADATA")
@Getter
@SuperBuilder
@AllArgsConstructor
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "FIELD_TYPE")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class FieldMetadata extends CreationAuditingEntity {

  @Id
  @Column(name = "FIELD_CD", length = 50, nullable = false)
  private String fieldCd;

  @Column(name = "LABEL", length = 50, nullable = false)
  private String label;

  @Enumerated(EnumType.STRING)
  @Column(name = "DATA_TYPE", columnDefinition = "varchar(20)", nullable = false)
  private FieldDataType dataType;

}

 

RealFieldMetadata (상속된 자식)


@Entity
@Table(name = "REAL_FIELD_METADATA")
@Getter
@SuperBuilder
@AllArgsConstructor
@DiscriminatorValue(FieldDiscriminatorValues.D_REAL)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@PrimaryKeyJoinColumn(name = "FIELD_CD")
public class RealFieldMetadata extends FieldMetadata {

  @Enumerated(EnumType.STRING)
  @Column(name = "TABLE_ALIAS", columnDefinition = "varchar(50)", nullable = false)
  private TableAlias tableAlias;

  @Column(name = "COLUMN_NAME", nullable = false, length = 50)
  private String columnName;

  @Builder.Default
  @Convert(converter = BooleanYNConverter.class)
  @Column(name = "REQUIRES_JOIN", nullable = false, columnDefinition = "char(1) default 'N'")
  private boolean requiresJoin = false;

  @Enumerated(EnumType.STRING)
  @Column(name = "JOIN_TABLE", columnDefinition = "varchar(50)")
  private TableAlias joinTable;


}


FieldGroupMapping 과 FieldMetadata는 1:N 관계입니다.

List<String> idList = List.of("GD01", "GD02", "GD03");
// fetch join 없이 조회 
List<FieldGroupMapping> fieldGroupMappings1 = fieldGroupRepository.findAllById(idList);

Long gridId = 1L;
// fetch join으로 조회
List<FieldGroupMapping> fieldGroupMappings2 = gridRepository.getGrid(gridId)
    .map(Grid::getFieldGroupMapping)
    .toList();

for (FieldGroupMapping mapping1 : fieldGroupMappings1) {
    FieldMetadata field = mapping1.getField();
    // 여기서 BreakPoint로 field를 보면 Proxy 객체
}

for (FieldGroupMapping mapping2 : fieldGroupMappings2) {
    FieldMetadata field = mapping2.getField()
    // 여기서 BreakPoint로 field를 보면 실제 객체 (Unproxy상태)
}

 

위 상황에서 첫번째 fieldGroupMappings1을 조회할땐 fetch join없이 hibernate로만 조회합니다.

두번째 fieldGroupMappings2를 조회할땐 Grid -> FieldGroupMapping -> field 연관관계 모두 fetch join을 써서 조회합니다.

 

제 지식으로는 두개 for문에서 모두 field는 Unproxy상태여야합니다.
단, fetch join이 없는 첫번째 리스트에서는 Select Query가 나가겠죠.

하지만, 테스트 결과는 첫번째 리스트에서의 field는 계속 Proxy상태로 되어있어. field 내부의 필드들이 null로 되어있었습니다.

 

또, 제 어플리케이션의 설정으로 default batch size는 1000으로 되어있어. select문의 조건에 in절로 채워져서 쿼리가 1번 발생하였습니다.

 

제 지식으로는 Select쿼리가 발생하였으므로, 첫번째 리스트도 field는 실제 객체여야하는데 왜 프록시객체로 남아있을까요? FieldMetadata 엔티티가 상속Entity여서 발생하는 문제일까요?

정답을 알려주세요 ㅠㅠㅠ

 

 

 

 

jpa hibernate

답변 1

0

인프런 AI 인턴

안녕하세요, 인프런 AI 인턴입니다.
papakang22님, 설명하신 문제를 바탕으로 Hibernate에서 발생할 수 있는 프록시 관련 이슈를 살펴보겠습니다.

첫 번째로, fetch join이 없는 경우에는 Hibernate가 연관된 객체를 필요 시점(즉, 실제 데이터 접근 시점)에 lazy loading을 통해 로딩합니다. 이때, FieldMetadata@ManyToOne 관계이므로 기본적으로 LAZY 로딩 전략을 사용합니다. 따라서 mapping1.getField() 호출 시 FieldMetadata의 실제 객체가 아닌 프록시 객체로 반환될 수 있습니다.

반면, 두 번째 케이스에서는 fetch join을 사용하여 쿼리 단계에서 필요한 데이터를 모두 가져오기 때문에 결과적으로 프록시 객체가 아닌 실제 객체로 로드됩니다.

두 경우 간의 차이는 @ManyToOne(fetch = FetchType.EAGER) 설정에 기인할 수 있습니다. EAGER 로딩 설정에도 불구하고 정상적으로 로딩되지 않는 경우가 발생할 수 있으므로, 다음을 확인해 보시는 것이 좋습니다:

  1. EntityManager Configuration: FetchType.EAGER로 설정했음에도 프록시 객체로 반환되는데는 여러 설정 및 환경적 요인이 있을 수 있으니, EntityManager 설정 및 환경을 확인해 보세요.

  2. Inheritance 전략: 상속 구조(@Inheritance(strategy = InheritanceType.JOINED))로 인해 문제 발생 가능성이 있을 수 있습니다. 이런 상황에서는 해당 객체의 타입 캐스팅 및 초기화 과정에서 문제가 발생할 수 있으므로 상속 구조 내의 설정을 확인해 보세요.

  3. Hibernate Initialization 호출: 명시적으로 초기화할 수 있도록 Hibernate.initialize(object)를 통해 프록시 객체를 초기화하는 것도 한 가지 방법입니다.

  4. Hibernate 버그 확인: 사용중인 Hibernate 버전에서 관련된 알려진 버그가 없는지 공식 문서를 통해 확인이 필요합니다.

아래의 Spring Data JPA 공식 문서도 도움이 될 수 있으니 참고 바랍니다:

위 방법으로 해결되지 않는다면, 환경 설정 상태를 좀 더 세부적으로 점검하시거나, 소규모 프로젝트로 테스트해보는 것도 좋은 방법일 수 있습니다. 추가적인 문제가 있으면 다시 질문 주시면 감사하겠습니다.

Inner class로 Config를 지정하는 이유

0

29

1

Part 2 듣기전 복습하던 중, 아키텍처에 관한 질문이 있습니다.

0

47

2

테스트는 인터페이스를 대상으로 만드는것에 대해 궁금한 점이 있습니다.

0

32

1

리뉴얼 시기

0

53

2

JPA 엔티티로 만들었다고 기술종속이 아닌지에 대한 질문

0

56

3

설계 트레이드 오프 링크 접속 안됨

0

85

2

테스트 질문, 어떤것을 사용할것인것에 대해서

0

46

1

service-discovery 프로세스 가동 이유

0

51

1

트래잭션 전파 기본- 에 대한 개념 질문? 이렇게 생각해도 맞나요?

0

47

1

헥사고날 아키텍처와 DDD를 적용할 때, 화면에 강하게 연관된 조회 데이터를 어떻게 다루는 게 좋은지 궁금합니다.

0

133

2

h2 database

2

59

2

Request DTO에서 Entity를 생성할 때 의존성 방향을 반대로 하면 어떨까요?

0

116

2

Querydsl 설정 할때 - run and test 다르게 설정 할때? 질문

0

61

1

new 패키지명.Dto명 생략가능

0

74

2

변경감지(더티체킹) 이후 플러시할 경우의 쿼리

0

73

1

단일 테이블 시 null 값과 연관관계 필요성 질문

0

65

1

SpringBoot4 버전 Hibernate5JakartaModule 라이브러리 오류

0

64

1

aws 관련 질문드립니다.

1

69

3

setter 사용하지 않기

0

61

1

안녕하세요 토비님 혹시 완성된 코드의 repository 주소는 없을까요?

0

127

2

자막 오타 제보

0

54

1

rabbitmq에 configservice 연결에 대해 질문있습니다.

0

65

1

안녕하세요 치킨 디도스 이벤트 보고 흉내내보려 들어왔습니다..

0

74

2

join에대해 질문드립니다.

0

55

1