카테고리 없음

최대 절전 모드 LAZY 로딩 및 스프링의 UserDetails

기록만이살길 2021. 3. 3. 08:04
반응형

최대 절전 모드 LAZY 로딩 및 스프링의 UserDetails

1. 질문(문제점):

상태 비 저장 REST 백엔드가 있습니다. 따라서 HTML보기가 없습니다. JSON 및 REST 엔드 포인트 만 있습니다. 인증은 Json 웹 토큰으로 수행됩니다. 클라이언트는 각 요청에서 JWT를 보냅니다. 내 백엔드는이 JWT의 제목 클레임에서 사용자의 이메일을 가져옵니다. 그런 다음 데이터베이스에서 UserModel을로드합니다.class LiquidoUserDetailsService implements UserDetailsService { ...}

각 사용자는 팀의 일부입니다. 하지만 팀은 많은 정보를 담고있는 큰 실체입니다. 따라서 팀은 필요할 때만 느리게로드됩니다.

UserModel.java

@Entity
@Table(name = "users")
public class UserModel extends BaseModel {
  @NotNull
  @NonNull
  @Column(unique = true)
  public String email;
  @ManyToOne(fetch = FetchType.LAZY)  // only load team info (with all info) if required
  public TeamModel team;

  [...]
}

이제 현재 사용자의 팀을 반환해야하는 서비스가 있습니다.

TeamService.java

@PreAuthorize(HAS_ROLE_USER)
@RequestMapping("/getOwnTeam")
@Transactional                          // [1] 
public TeamModel getOwnTeam() {
  // Get currently logged in user (that was loaded with info from JWT)
  Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
  LiquidoAuthUser authUser = (LiquidoAuthUser)authentication.getPrincipal();
  // LiquidoAuthUser is the Adapter betwen spring's User and my USerModel
  UserModel currentUser = authUser.getLiquidoUserModel()    

  TeamModel team = currentUser.getTeam()     // <=== [2] throws LazyInitializationException

  return team
}

이제 나는 문제가 어디에 있는지 알고 있다고 생각합니다. 그러나 나는 아직 그것에 대한 깨끗한 해결책이 없습니다.

My UserModel class LiquidoUserDetailsService implements UserDetailsService이로 드되지만 이는 HTTP 요청이 처리 될 때 필터에서 매우 일찍 발생합니다. 그것은 솔기로 @Transaction내에서 TeamService클래스 아직 그 시간에 시작되지 않습니다.

그런 다음 코드가 getOwnTeam()메소드에 입력되면 트랜잭션이 시작됩니다 [1]. 그러나 거기에서 더 이상 사용자 팀을 지연로드 할 수 없습니다. [2]

사용자와 팀을 어떻게 모델링하여

  1. 팀 데이터는 필요한 경우에만로드됩니다.
  2. 내가 때이 켜지지 수동으로 데이터를로드

2. 해결방안:

다른로드 시작이 필요한 경우 다음을 사용할 수 있습니다.

  1. 쿼리시 네이티브 SQL
  2. 조인 가져 오기와 같은 구성이있는 jpql
  3. 엔티티 그래프 ( https://www.baeldung.com/jpa-entity-graph ) 이러한로드 방법을 사용할 때의 주요 이점은 데이터베이스에 대한 단일 요청입니다. 자세한 내용은 https://thorben-janssen.com/lazyinitializationexception/을 읽을 수 있습니다.

분리 된 상태의 객체-이것은 LazyInitializationException의 이유입니다 (객체를로드하기 위해 다른 상태로 이동).

entityManager.merge(deatachedEntity);
65752757
반응형