【问题标题】:Spring JPA, Lazy Initialization and Dto [duplicate]Spring JPA,延迟初始化和 Dto [重复]
【发布时间】:2021-04-03 19:26:42
【问题描述】:

我正在尝试获取用户登录后的个人资料数据(来自登录成功过滤器),但我看到延迟加载数据时出现异常。请看以下示例代码:

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);
    }
}

UserLoginResponseDto.java

public class UserLoginResponseDto {

    private UUID id;
    private String email;
    private List<RoleModel> roles;

}

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

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

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

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

【问题讨论】:

    标签: java hibernate jpa dto


    【解决方案1】:

    您的问题是您将实际的懒惰List 传递给setRoles,这不会触发完全加载。这(立即)表明,虽然您已将顶级数据库类与顶级 DTO 分离,但这是一种“浅层”分离,并未完全实现这些值。您还没有显示 RoleModel 是实体还是可嵌入的,这很重要。

    所以第一步是将项目复制到非 JPA 表单中。如果 RoleModel 可嵌入(本质上是 POJO),则可以像 setRoles(new ArrayList&lt;&gt;(roles)) 一样简单。否则,您需要一个嵌套的 DTO,此时可能会考虑使用 MapStruct 之类的东西。

    不过,无论哪种情况,您都可能遇到N+1 问题。实际上,您确实想要一个急切的获取在这种情况下,这就是 JPA 实体图的用途。您可以告诉 Spring Data 仅在需要时才急切地获取列表,这是何时执行此操作的完美示例。

    【讨论】:

    • RoleModel 是一个实体,我们可以从这个映射中看到:@OneToMany(cascade = { CascadeType.ALL }) private List&lt;RoleModel&gt; roleModels;
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-01
    • 2015-11-01
    • 2015-08-08
    • 1970-01-01
    • 1970-01-01
    • 2014-06-12
    相关资源
    最近更新 更多