2010-03-15 4 views
7

이상이있을 경우 수정하십시오.DAO, Spring 및 Hibernate

이제 ORM 템플릿 용 Spring DAO를 사용할 때 @Transactional 특성을 사용하면 메서드 내에서가 아니라 메서드가 호출 될 때 트랜잭션 및/또는 세션을 제어 할 수 없습니다.

지연로드는 리소스를 절약 해줍니다. 데이터베이스에 쿼리하는 횟수가 줄어들어 모든 컬렉션을 앱 메모리에 가져올 수 있습니다.

lazy = false이면 모든 관련 콜렉션이 페치됩니다. 즉, 연결된 세트에 10,000 개의 레코드가있는 경우 효과적이지 않습니다.

이제 사용자 개체를 반환해야하는 DAO 클래스에 메서드가 있습니다. 데이터베이스의 연결된 테이블을 나타내는 컬렉션이 있습니다. ID로 개체를 가져온 다음 컬렉션에 쿼리해야합니다.

Hibernate는 "DAO 메소드가 리턴하는 링크 된 콜렉션에 액세스하려고 할 때 예외적으로 콜렉션을 초기화하지 못했습니다"예외가 발생합니다.

설명해주십시오. 해결 방법은 무엇입니까?

업데이트 : 알겠습니다. DAO는 추상 레이어이므로 "getUserById (Integer id)"메서드는 Object를 반환해야합니다.

어떤 경우에는 User 개체의 이러한 연결된 컬렉션이 필요하고 다른 상황에서는 해당 컬렉션이 필요한 경우 어떻게합니까? getUserByIdWithTheseCollections(), getUserByIdWithOtherCollections() 및 그 방법 안에 당신의 접근 방식을 사용 2) 다른 방법을 만들 = 거짓 1) 지연로드 :

는 두 가지 방법이 있습니까?

내 말은 단지 2 가지 밖에 없으며 더 좋은 점은없는 것입니까?

업데이트 2 : 설명해주십시오. SESSIONFACTORY를 명시 적으로 사용하게하려면 어떻게해야합니까? 실제로 어떻게 보이나요? 우리는 DAO 객체의 인스턴스 인 을 세션 팩토리에 삽입합니다. 그러면 두 개의 결과적으로 DAO에 대한 메서드 호출이 동일한 트랜잭션 내에서 실행됩니다. 어쨌든, DAO는 그것을 사용하는 수업에서 분리됩니다!

논리와 트랜잭션은 DAO 내에 캡슐화됩니다. 맞습니까? BalusC가 지적했듯이

User user = sessionFactory.getCurrentSession().get(User.class, userId); 
user.getLinkedCollection().size(); 
return user; 

, 당신은 Hibernate.initialize() 대신 size() 사용할 수 있습니다 : 당신이 트랜잭션 내에서 여전히있는 동안

답변

6

당신은 그것을로드 트랜잭션에서 링크 모음을 얻을 수 있습니다. 그것은 훨씬 더 깨끗합니다.

그런 엔티티를 반환하면 게으른 필드가 이미 초기화됩니다.

귀하의 PS에 회신 - 가능한 서비스 수준 (DAO가 아닌) 수준의 트랜잭션을 사용하고 있습니까? 각각의 DAO 호출을 별도의 트랜잭션으로 수행하는 것이 낭비 인 것처럼 보일 수도 있습니다 (올바르지 않을 수도 있음).

+0

@Konrad Garus 질문에 대한 내 포스트 스크립트를 참조하십시오. 여기 텍스트는 읽기 쉽지 않으므로 거기에서 묻습니다. – EugeneP

+0

@EugeneP 업데이트 된 답변보기. –

5

@Transactional을 DAO 레이어가 아닌 서비스 레이어에 배치하는 것이 가장 좋습니다. 그렇지 않으면 모든 DAO 호출은 별도의 최대 절전 모드 세션에 있으며 모든 객체 평등 항목은 작동하지 않습니다.

+1

SpringDAO로 작업 할 때이를 처리하는 좋은 방법입니다. –

1

제 생각에는이 문제를 해결하는 가장 좋은 방법은 요청 당 세션 모델에서 응용 프로그램을 디자인하는 것입니다. 그런 다음 DAO에서 가져온 객체가있는 경우에도 OSIV 패턴이 작동 할 때까지 응용 프로그램에서 객체를 안전하게 사용할 수 있습니다.이 객체를 신경 쓰지 않고도 뷰에서 사용할 수 있습니다. 이것은 그 제안 더 나은 솔루션 아마도 이유는

  1. 들 Hibernate.initialize() 또는 크기가 매우 인공적인 해결 방법 - 당신은 초기화 다른 컬렉션 사용자를하려는 경우, 사용자를 얻기위한 다른 방법을 쓰는 것이 무엇?
  2. 서비스 층 트랜잭션 모델은 OK입니다,하지만 당신은
1

당신은 다음과 같은 것을 할 수있는 컨트롤러 나보기에서 사용하는 서비스 계층에서 추출 된 개체를 가져 할 때 같은 문제가 온다 :

public User getByUserId(Long id, String ... fetch) { 
    Criteria criteria = createCriteria(); 

    if (fetch != null) { 
     for (String fieldName : fetch) { 
      criteria.setFetchMode(fieldName, FetchMode.JOIN); // fetch these fields eagerly 
     } 
    } 
    return criteria.add(Restrictions.eq("id", id)).list(); 
}