Hibernate LAZY加载和spring的UserDetails [英] Hibernate LAZY loading and spring's UserDetails

查看:50
本文介绍了Hibernate LAZY加载和spring的UserDetails的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个无状态的REST后端.因此没有HTML视图.只是JSON和REST端点.身份验证是通过Json Web令牌完成的.客户端在每个请求中发送一个JWT.我的后端从此JWT中的主题声明中获取用户的电子邮件.然后,它从数据库中的类LiquidoUserDetailsS​​ervice实现UserDetailsS​​ervice {...}

I have a stateless REST backend. So no HTML views. Just JSON and REST endpoints. Authentication is done with Json Web Tokens. The client sends a JWT in each request. My backend takes the user's email from the subject claim in this JWT. Then it loads the UserModel from the database in class LiquidoUserDetailsService implements UserDetailsService { ...}

每个用户都是团队的一部分.但是团队是一个庞大的实体,其中包含许多信息.因此,只有在必要时才懒惰地加载团队:

Each user is part of a team. But the Team is a big entity with a lot of information in it. So teams are only loaded lazily, when necessary:

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;

  [...]
}

现在,我有一项服务应返回当前用户的团队:

Now I have a service that should return the team of the current user:

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
}

现在我想我知道问题出在哪里了.但是我还没有一个干净的解决方案.

Now I think I know where the problem is. But I do not yet have a clean solution for it.

我的UserModel加载在类LiquidoUserDetailsS​​ervice实现UserDetailsS​​ervice 中,但是这很早就在过滤器中处理HTTP请求时发生.由于它在我的 TeamService 类中的 @Transaction 当时尚未启动,所以尚未启动.

My UserModel is loaded in class LiquidoUserDetailsService implements UserDetailsService But this happens very early, in a filter, when the HTTP request is processed. As it seams the @Transaction in my TeamService class is not yet started at that time.

然后,当代码输入 getOwnTeam()方法时,将启动 new 事务[1].但是在那里,我不能再懒惰地加载用户团队了.[2]

Then when the code enters the getOwnTeam() method, a new transaction is started [1]. But in there I cannot lazy load the user's team anymore. [2]

如何为用户和团队建模,以便

  1. 仅在必要时加载团队数据
  2. 可以在必要时手动加载数据
  1. The team data is only loaded when necessary
  2. I can load the data manually when neccessary

推荐答案

如果您需要不同的负载启动方式,则可以使用:

If you need different load startegy you can use:

  1. 查询时的本机sql
  2. jpql具有类似join fetch的构造
  3. 实体图( https://www.baeldung.com/jpa-entity-graph )使用这种方式加载的主要好处是对数据库的单个请求.您可以阅读更多 https://thorben-janssen.com/lazyinitializationexception/
  1. Native sql when query
  2. jpql with construction like join fetch
  3. Entity Graph (https://www.baeldung.com/jpa-entity-graph) The main benefit when you use such way to load is single request to database. You can read more https://thorben-janssen.com/lazyinitializationexception/

您的对象处于分离状态-这是LazyInitializationException的原因(您可以将其移动到其他状态以加载您的对象)例如

Your object in deatached state - this is reason of LazyInitializationException (you cat move it to other state to load your object) for example

entityManager.merge(deatachedEntity);

这篇关于Hibernate LAZY加载和spring的UserDetails的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆