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
'programing' 카테고리의 다른 글
어레이에서 구성 요소 삭제, vuejs에서 잘못된 구성 요소 제거 (0) | 2022.08.24 |
---|---|
Vue에서 계산된 속성이 감시를 트리거하지 않습니다. (0) | 2022.08.24 |
'in' 연산자를 사용하여 정의되지 않은 'X'를 검색할 수 없습니다. (0) | 2022.08.24 |
지원되지 않거나 구현되지 않은 작업에 대해 Java에서 발생하는 표준 예외는 무엇입니까? (0) | 2022.08.24 |
vuejs v-on에서 Chrome이 작동하지 않음:옵션 태그를 클릭합니다. (0) | 2022.08.24 |