Hibernate LAZY加载和spring的UserDetails [英] Hibernate LAZY loading and spring's UserDetails
问题描述
我有一个无状态的REST后端.因此没有HTML视图.只是JSON和REST端点.身份验证是通过Json Web令牌完成的.客户端在每个请求中发送一个JWT.我的后端从此JWT中的主题声明中获取用户的电子邮件.然后,它从数据库中的类LiquidoUserDetailsService实现UserDetailsService {...}
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加载在类LiquidoUserDetailsService实现UserDetailsService
中,但是这很早就在过滤器中处理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]
如何为用户和团队建模,以便
- 仅在必要时加载团队数据
- 我可以在必要时手动加载数据
- The team data is only loaded when necessary
- I can load the data manually when neccessary
推荐答案
如果您需要不同的负载启动方式,则可以使用:
If you need different load startegy you can use:
- 查询时的本机sql
- jpql具有类似join fetch的构造
- 实体图( https://www.baeldung.com/jpa-entity-graph )使用这种方式加载的主要好处是对数据库的单个请求.您可以阅读更多 https://thorben-janssen.com/lazyinitializationexception/
- Native sql when query
- jpql with construction like join fetch
- 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屋!