2010-04-07 5 views
4

데이터베이스에서 개체를 반환하는 DAO를 호출하는 서비스 메서드가 있습니다. 이 메소드는 시스템의 여러 부분에서 호출됩니다. 그러나 한 가지 특별한 방법은 유형으로 ObjectClass _ $$ _ javassist_somenumber의 반환 유형을 얻는 것입니다. 어느 것이 사물을 던지고 있습니다. 저는 서비스 메소드를 다른 곳과 똑같이 호출합니다. 그래서 왜 자연수와 반대로 동면을 반환할까요?왜 Hibernate가 프록시 객체를 반환하나요?

"프록시 된"개체를 노출하는 방법이 있지만 그 작업을 수행해야한다고 생각하지 않습니다.

쿼리는 단순히 내가 BTW 3.3 최대 절전 모드 사용하고

hibernateTemplate.find("from User u where u.username = ?", username) 

입니다.

답변

9

지연로드를 지원하기 위해 프록시 된 객체입니다. 기본적으로 액세서/getter 메서드를 통해 자식 또는 조회 객체를 참조하는 즉시 링크 된 엔터티가 세션 캐시에 없으면 프록시 코드가 데이터베이스로 이동하여 링크 된 객체를로드합니다. javassist을 사용하여 객체의 하위 클래스 구현을 효과적으로 동적으로 생성합니다 (비록 CGLIB을 사용하도록 구성 할 수 있다고 생각하지만).

이 방법으로 프록시되지 않은 경우 원활한 지연로드를 구현하는 것은 거의 불가능합니다.

열렬한로드를 사용하고 자연물이 대신 반환되는지 여부를 기억하지 못합니다. 일반적으로 링크 된 하위 엔티티가 많은 경우 열심히로드하는 것이 좋습니다. 메모리에 연결된 모든 객체를 빨아 들이기 때문에 곧 성능 병목 현상이 될 수 있습니다. 또한

, 당신이 상관없이 proxed 여부에 자연 개체 클래스를 다시 줄 것이다 Hibernate.getClass(obj)를 사용하지 않고 obj.getClass()을 사용하는 것보다, 클래스 종류에 구별해야하는 경우 : 하이버 네이트 API Javadoc과 here를 참조하십시오. 제 생각에는

+0

그럼 개체가 열심히로드되고 이후 프록시 개체를 받고 있어요 이 특정한 호출, 나는 당신이 그 객체가 어느 것이 든 될 것이라고 짐작할 수 없을 것입니다. 흥미롭게도 tho는 메서드 A에서 DAO.getUser (String username)을 호출 할 때 User 객체를 얻지 만 메서드 B에서 메서드가 동일한 매너를 호출하면 프록시가 생깁니다. – predhme

+1

일반적으로 문제는 프록시 *가 이와 같이 반환된다는 것입니다. * 올바르게 초기화되지 않았습니다. 그렇지 않으면 제대로 채워지면 상황이 정상적으로 처리되어야합니다. find 메소드가 초기화되지 않은 프록시를 반환하는 이유는 누구나 아는가? –

2

Hibernate는 모든 멤버가 해결되지 않은 경우, 즉 객체가 완료되지 않은 경우 프록시를 반환합니다. 이것은 종종 성능을 향상시키는 데 필요한 기능이며 최대 절전 모드의 기본 설정입니다.

프록시를 원하지 않으면 hbm.xml 파일에서 지연로드를 억제 할 수 있습니다. 즉 eager loading을 사용합니다. 정확한 구문은 Hibernate 문서를 확인하십시오.

프록시 개체를 사용하려면 멤버 함수 내에서도 직접적으로 액세스하지 말고 getter를 통해서만 액세스하십시오. 당신이 그것을 얻을 때 최대 절전 모드의 마법은 회원을 채 웁니다. 이렇게하면 객체를 노출 할 필요가 없습니다. 또한 잠재적 인 프록시 객체에서 instanceof를 사용하지 마십시오. 그러나 이것은 어쨌든 코드 냄새입니다.

+2

프록시는 여전히 클래스의 하위 클래스 인스턴스이기 때문에 인스턴스 검사가 계속 작동합니다. 무엇이 작동하지 않는 것은 (getClass()에 의해 제공되는) 클래스 객체의 equals 또는 identity 비교입니다. – whiskeysierra

+0

이 문제가 발생했는데 위의 문구가 올바르지 않은 것으로 밝혀졌습니다. 문제가있는 방식입니다. 우리는 컬렉션을 반복하고 실패한 예상 객체에 대해 'instanceof'를 확인합니다. 솔직히 java가 내부적으로 이것을 처리하는 방법을 정확히 알지 못하지만 "instanceof x ="+ (obj instanceof x)와 함께 println을 넣으면 false가 출력됩니다. Hibernate.getClass (obj)는 훌륭하게 작동하지만, 객체가 완전히 초기화되지 않은 이유의 맨 아래로 가고 싶습니다. – mikemil

+0

@whiskeysierra - 죄송합니다, 위의 의견에 대한 통보를 위해 귀하의 ID를 포함하는 것을 잊었습니다. – mikemil

0

이 표현 :

hibernateTemplate.find("from User u where u.username = ?", username) 

항상 POJO가 아닌 프록시를 반환해야합니다. 이는 표준 HQL/criteria가 프록시되지 않은 객체가 아니라 원래의 엔티티 클래스의 객체를 반환하기 때문입니다. 이 lazy 연관 가져 오는 다른 :

@Entity 
class X { 
    @ManyToOne(fetch = FetchType.LAZY) 
    private User user; 
} 

여기 dB에서 X 객체를 얻기, 우리는 X.user 필드 (A 프록시 User 예)에서 게으른 프록시를해야합니다.

이제 from User where [...]을 수행하면 POJO와 프록시 객체가있는 경우가 있습니다. 대개 일부 실행에서는 User 객체가 db를 통해 연관을 통해 처음으로 가져 오기 (from X where [...] 쿼리가 주어진 최대 절전 모드 세션에서 처음 호출 되었기 때문)입니다. 이미 User 인스턴스를 가지고 있으면 (hibernate는 from User where [...]과 같은 일반 쿼리에 대해서도이 인스턴스를 재사용 할 것입니다.)

관련 문제