Hibernate LAZY loading and spring's UserDetails

北战南征 提交于 2021-01-25 08:06:08

问题


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.

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.

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]

How can I model my users and teams, so that

  1. The team data is only loaded when necessary
  2. I can load the data manually when neccessary

回答1:


If you need different load startegy you can use:

  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/

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


来源:https://stackoverflow.com/questions/65752757/hibernate-lazy-loading-and-springs-userdetails

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!