Spring JPA, Lazy Initialization and Dto



我试图在登录后(从登录成功过滤器(获取用户的配置文件数据,但我看到Lazy加载数据时出现异常。请参阅以下示例代码:

AuthenticationSuccessHandler.java

@Component
public class AuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
@Autowired
private UserService userService;
@Autowired
private Gson gson;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws ServletException, IOException {
User user = (User) authentication.getPrincipal();
UserLoginResponseDto userLoginResponseDto = userService.login(user.getUsername());
response.setStatus(HttpStatus.OK.value());
response.setContentType("application/json; charset=UTF-8");
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
response.getWriter().println(gson.toJson(userLoginResponseDto));
response.getWriter().flush();
clearAuthenticationAttributes(request);
}
}

UserService.java

public class UserService implements UserDetailsService, TokenService {
@Autowired
private UserRepository userRepository;
@Transactional(readOnly = true)
public UserLoginResponseDto login(String email) {
Optional<UserModel> userOptional = userRepository.findByEmailIgnoreCase(email);
UserModel userModel = userOptional.get();
UserLoginResponseDto userLoginResponseDto = userModel.toUserLoginResponseDto();
return userLoginResponseDto;
}
}

UserModel.java

public class UserModel {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(nullable = false, unique = true, updatable = false)
private UUID id;

[A FEW MORE FIELDS]
@Column(length = 256, nullable = false, unique = true, updatable = false)
private String email;
@OneToMany(cascade = { CascadeType.ALL })
private List<RoleModel> roleModels;
public UserLoginResponseDto toUserLoginResponseDto() {
return new UserLoginResponseDto().setId(id).setEmail(email).setRoles(roleModels);
}
}

UserLoginResponseTo.java

public class UserLoginResponseDto {
private UUID id;
private String email;
private List<RoleModel> roles;
}

当UserLoginResponseTo类型的对象在AuthenticationSuccessHandler中序列化时,我看到以下错误消息-

org.hibernate.LazyInitializationException:未能延迟初始化角色集合:UserModel.roleModels,无法初始化代理-无会话

QQ-如何在不使用以下任何技术的情况下正确解决此问题?

  • [ANTIPATTERN]在视图中打开
  • [反模式]hibernate.enable_lazy_load_no_trans
  • FetchType.EAGER

您的问题是将实际的懒惰List传递到setRoles中,这不会触发满载。这(立即(表明,当您将顶级数据库类与顶级DTO分离时;浅";分离,这并没有完全体现价值观。您还没有显示RoleModel是实体还是可嵌入的,这很重要。

因此,第一步是将项复制到一个非JPA表单中。如果RoleModel是可嵌入的(本质上是一个POJO(,这可能和setRoles(new ArrayList<>(roles))一样简单。否则,您需要一个嵌套的DTO,此时可能会考虑类似MapStruct的东西。

然而,在任何一种情况下,您都可能遇到N+1问题。事实上,确实想要一个急切的获取,在这种情况下,这就是JPA实体图的用途。您可以告诉SpringData只有在需要的时候才急切地获取列表,这是一个很好的例子。

最新更新