2017-12-27 5 views
1

업데이트NullPointerException가 최대 절전 모드 withi 봄 부팅

내가 @ sainr의 대답 Converting Hibernate proxy to real entity object이 문제를 해결 않습니다 싶습니다 FetchType.LAZY으로 발생합니다. 그러나이 장면의 문제는 내 SiteEntityfinal 수식어가 setControllerEntity이고 getControllerEntity인데 내 질문에 제기하지 않았습니다. 그리고 나는 사과한다.

final 수정자를 제거하십시오. 그런 다음 Hibernate는 프록시 객체를 잘 초기화 할 수있다.

설명은 스택 오버플로의 answer에서 찾을 수 있습니다. 나는 장치 개체를 발견 한 후

@Entity 
@Table(name = "controller") 
public class ControllerEntity { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(nullable = false, updatable = false) 
    private long id; 
} 

@Entity 
@Table(name = "site") 
public class SiteEntity { 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(nullable = false) 
    private long id; 

    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "controller_id", nullable = false) 
    private ControllerEntity controllerEntity; 
} 

@Entity 
@Table(name = "device") 
public class DeviceEntity { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(nullable = false) 
    private long id; 

    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "site_id", nullable = true) 
    private SiteEntity siteEntity; 
} 

을 다음과 같은


내가 세 가지 요소를 가지고, 나는 그것에서 직접 controllerEntity를 얻을하려고합니다.

final DeviceEntity deviceEntity1 = deviceRepository.findOne(1L); 
System.out.println(deviceEntity1.getSiteEntity().getControllerEntity().getId()); 

하지만 그것은 siteEntity에서 nullcontrollerEntity 의해 발생되는 결과 java.lang.NullPointerException.

siteRepositoy을 사용하여 siteEntity를 다시 가져 오려고 했는데도. 그 중 controllerEntity은 여전히 ​​null입니다.

DeviceEntity와 SiteEntity 둘 다에서 fetch = FetchType.LAZY을 제거한 후 NPE가 더 이상 발생하지 않습니다.

하지만 이상하게 보입니다. 최대 절전 모드에서 올바른 값을 가져 오는 것을 기대하면서 FetchType.LAZY을 사용할 수 있습니까?

감사합니다.

답변

2

Hibernate는 FetchType.LAZY으로 선언 된 필드에 대한 액세스 권한을 부여하기 위해 CGLIB를 사용하여 프록시를 생성합니다. 결과적으로 그러한 필드에 getter를 호출하면 (예 : getSiteEntity() 또는 getControllerEntity()) 직접 필드 값에 액세스하지 않고 대신 Hibernate의 프록시 객체로 전달됩니다. 반대로, Hibernate는 데이터 저장소로부터 실제 값을로드하려고 시도하고 이것을하기 위해 DB에 접근하기 위해 액티브 Hibernate 세션이 필요하다. 대부분의 경우, 당신의 경우에, Hibernate 세션은 이미 닫혀 있고 그러한 게으른로드는 실패하여 필드의 값은 실질적으로 null이다.(Converting Hibernate proxy to real entity object 확인) 실제 객체로 프록시 개체를 변환

  1. 사용 FetchType.EAGER 유지 객체 DeviceEntity
  2. 과 함께 모든 필드 값을로드 할 것이라고 및 액세스 :

    은 기본적으로 두 가지이 문제를 해결하는 방법이 있습니다 규칙적인 방식으로하십시오.

실제로 당신의 경우에 게으른로드가 필요한지 여부를 생각해보십시오. 필요에 따라로드 할 어린이 필드에 무거운 물건을 많이 저장하지 않으면 FetchType.EAGER으로 전환하는 것이 가장 쉬운 방법입니다.

희망이 있습니다.

+1

고마워. 그것은 실제로 무거운 물체를 포함하지 않습니다. 대신에 EAGER로 전환하겠습니다. 그러나 무거운 개체 또는 ManyToMany, OneToMany 매핑과 같은 FetchType.LAZY에 대한 필요성이있는 경우 절전 모드 세션이 닫히거나 "프록시 개체를 실제 개체로 변환"하는 것을 방지하기 위해 어쨌든 갈 수 있습니까? 감사합니다 – Chiu

+1

@Chiu 당신은'TransactionTemplate' 내에서 사용하려고 시도 할 수 있습니다 (또는 홀더 객체를로드하고'@ Transactional'으로 게으른 자식에 접근하는 메소드를 표시 할 수 있습니다) – sainr

+1

"최대 절전 모드 프록시를 실제 엔티티로 변환하기" 객체 "가 문제를 해결합니다. 그러나 장면 뒤에있는 문제는'SiteEntity'의'final' 수정자인'setControllerEntity'와'getControllerEntity'입니다. 'final' 수정자를 제거하십시오. 그러면 Hibernate는 프록시 객체를 잘 초기화 할 수있다. – Chiu

2

Hibernate는 때로는 그리 좋지 않은 원시 타입을 사용합니다. 이 래퍼 클래스 대신 기본 형식을 사용하는 것이 좋습니다

private long id 

최대 절전 모드에서 기본 키에 대한

private Long id 

에 교체하려고합니다.

+0

고마워요! 나는 원시 타입의 널 값을 어떻게 처리하는지에 대한 최근 연구에서 이것을 발견했다. – Chiu

관련 문제