programing

FetchType을 가져오는 방법.스프링 컨트롤러에서 JPA 및 휴지 상태와의 LAGY 관련성

prostudy 2022. 8. 24. 23:42
반응형

FetchType을 가져오는 방법.스프링 컨트롤러에서 JPA 및 휴지 상태와의 LAGY 관련성

개인 클래스가 있습니다.

@Entity
public class Person {

    @Id
    @GeneratedValue
    private Long id;

    @ManyToMany(fetch = FetchType.LAZY)
    private List<Role> roles;
    // etc
}

게으른 다대다 관계.

컨트롤러에는

@Controller
@RequestMapping("/person")
public class PersonController {
    @Autowired
    PersonRepository personRepository;

    @RequestMapping("/get")
    public @ResponseBody Person getPerson() {
        Person person = personRepository.findOne(1L);
        return person;
    }
}

PersonRepository는 이 가이드에 따라 작성된 코드입니다.

public interface PersonRepository extends JpaRepository<Person, Long> {
}

다만, 이 컨트롤러에서는, 실제로는 게으른 데이터가 필요합니다. 로드를 트리거하려면 어떻게 해야 합니까?

접속을 시도하면 다음과 같이 실패합니다.

역할 컬렉션 no.sysken.momus.model을 느리게 초기화하지 못했습니다.Person.roles, 프록시를 초기화할 수 없음 - 세션 없음

아니면 제가 하는 것에 따라 다른 예외들도 있어요.

필요에 따라 xml-description.

고마워요.

lazy 컬렉션을 초기화하려면 lazy 컬렉션을 명시적으로 호출해야 합니다(통상은 콜을 하는 것입니다)..size()(이 목적을 위해서)휴지 상태에서는, 전용의 방법이 있습니다(Hibernate.initialize()JPA는 이에 해당하지 않습니다.물론 세션이 아직 사용 가능할 때 호출이 완료되었는지 확인해야 합니다.따라서 컨트롤러 메서드에 주석을 붙입니다.@Transactional또 다른 방법은 컨트롤러와 저장소 사이에 레이지 컬렉션을 초기화하는 방법을 노출시킬 수 있는 중간 서비스 계층을 만드는 것입니다.

업데이트:

위의 솔루션은 간단하지만 데이터베이스에 대한 두 개의 개별 쿼리(사용자용 쿼리, 역할용 쿼리)가 생성됩니다.성능을 향상시키려면 다음 방법을 Spring Data JPA 저장소 인터페이스에 추가합니다.

public interface PersonRepository extends JpaRepository<Person, Long> {

    @Query("SELECT p FROM Person p JOIN FETCH p.roles WHERE p.id = (:id)")
    public Person findByIdAndFetchRolesEagerly(@Param("id") Long id);

}

이 메서드는 JPQL의 fetch join 절을 사용하여 데이터베이스에 대한 단일 라운드 트립으로 역할 관련성을 로드하기 때문에 위의 솔루션에서 두 개의 서로 다른 쿼리로 인해 발생하는 성능 저하를 완화합니다.

오래된 투고입니다만, @NamedEntityGraph(Javax Persistence)와 @EntityGraph(Spring Data JPA)의 사용을 검토해 주십시오.조합이 잘 된다.

@Entity
@Table(name = "Employee", schema = "dbo", catalog = "ARCHO")
@NamedEntityGraph(name = "employeeAuthorities",
            attributeNodes = @NamedAttributeNode("employeeGroups"))
public class EmployeeEntity implements Serializable, UserDetails {
// your props
}

그리고 봄 레포는 아래와 같습니다.

@RepositoryRestResource(collectionResourceRel = "Employee", path = "Employee")
public interface IEmployeeRepository extends PagingAndSortingRepository<EmployeeEntity, String>           {

    @EntityGraph(value = "employeeAuthorities", type = EntityGraphType.LOAD)
    EmployeeEntity getByUsername(String userName);

}

몇 가지 옵션이 있습니다.

  • 초기화된 엔티티를 R로 반환하는 저장소에 메서드를 작성합니다.J가 제안했다.

더 많은 작업과 최고의 퍼포먼스.

  • OpenEntityManager 사용InViewFilter: 요청 전체에 대해 세션을 열어 둡니다.

작업이 적습니다.일반적으로 웹 환경에서 허용됩니다.

  • 필요에 따라 도우미 클래스를 사용하여 엔티티를 초기화합니다.

작업량이 적어 OEMIV가 옵션(Swing 애플리케이션 등)이 아닌 경우 유용하지만 저장소 구현에서는 엔티티를 한 번에 초기화할 수 있습니다.

마지막 옵션으로는 유틸리티 클래스 JpaUtils를 작성하여 어떤 deph에서 엔티티를 초기화했습니다.

예를 들어 다음과 같습니다.

@Transactional
public class RepositoryHelper {

    @PersistenceContext
    private EntityManager em;

    public void intialize(Object entity, int depth) {
        JpaUtils.initialize(em, entity, depth);
    }
}

데이터JpaRepository

데이터JpaRepository 두 방법을 합니다. 즉, 2가지 방법이 있습니다.

  • getOne이 명령어는 에 대한 설정에 적합한 엔티티 프록시를 반환합니다.@ManyToOne ★★★★★★★★★★★★★★★★★」@OneToOne하위 엔티티를 유지할 때 상위 연결.
  • findById한 후

, 어느 쪽에도 .getOne ★★★★★★★★★★★★★★★★★」findById:

Person person = personRepository.findOne(1L);

아마 '아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 네'findOne는 method에서 입니다.PersonRepository 단,입니다.★★★★★★★★★★★★★★★★★ 。findOne당신의 경우 방법은 그다지 유용하지 않습니다.「 」를 가 있기 에, 「 」를 할 필요가 있습니다.Person ★★★★★★★★★★★★★★.roles더 것 같아요.findOneWithRoles대신 메서드를 사용합니다.

커스텀 스프링 데이터 방식

'어울릴 것 같다'를 할 수 .PersonRepositoryCustom뭇매를 맞다

public interface PersonRepository
    extends JpaRepository<Person, Long>, PersonRepositoryCustom { 

}

public interface PersonRepositoryCustom {
    Person findOneWithRoles(Long id);
}

그 실장을 다음과 같이 정의합니다.

public class PersonRepositoryImpl implements PersonRepositoryCustom {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public Person findOneWithRoles(Long id)() {
        return entityManager.createQuery("""
            select p 
            from Person p
            left join fetch p.roles
            where p.id = :id 
            """, Person.class)
        .setParameter("id", id)
        .getSingleResult();
    }
}

바로 그거야!

트랜잭션 중에만 느긋하게 로드할 수 있습니다.따라서 트랜잭션이 있는 저장소의 컬렉션에 액세스하거나 보통 fetchmode를 eager로 설정할 수 있습니다.

Open Session이 필요할 것 같아요.InViewFilter를 사용하여 뷰 렌더링 중에 세션을 열어 둡니다(단, 그다지 좋은 방법은 아닙니다).

다음과 같이 할 수 있습니다.

@Override
public FaqQuestions getFaqQuestionById(Long questionId) {
    session = sessionFactory.openSession();
    tx = session.beginTransaction();
    FaqQuestions faqQuestions = null;
    try {
        faqQuestions = (FaqQuestions) session.get(FaqQuestions.class,
                questionId);
        Hibernate.initialize(faqQuestions.getFaqAnswers());

        tx.commit();
        faqQuestions.getFaqAnswers().size();
    } finally {
        session.close();
    }
    return faqQuestions;
}

컨트롤러의 faqQuestions.getFaqAnswers().size()nin을 사용하면 목록 자체를 가져오지 않고도 쉽게 초기화된 목록을 얻을 수 있습니다.

언급URL : https://stackoverflow.com/questions/15359306/how-to-fetch-fetchtype-lazy-associations-with-jpa-and-hibernate-in-a-spring-cont

반응형