spring - Hibernate LAZY 加载和 spring 的 UserDetails
问题描述
我有一个无状态的 REST 后端。所以没有 HTML 视图。只是 JSON 和 REST 端点。使用 Json Web 令牌完成身份验证。客户端在每个请求中发送一个 JWT。我的后端从这个 JWT 中的主题声明中获取用户的电子邮件。然后它从数据库中加载 UserModelclass LiquidoUserDetailsService implements UserDetailsService { ...}
每个用户都是团队的一部分。但是团队是一个很大的实体,里面有很多信息。所以团队只会在必要时懒惰地加载:
用户模型.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;
[...]
}
现在我有一个服务应该返回当前用户的团队:
团队服务.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
}
现在我想我知道问题出在哪里了。但我还没有一个干净的解决方案。
我的 UserModel 已加载class LiquidoUserDetailsService implements UserDetailsService
但是这很早就发生在过滤器中,当 HTTP 请求被处理时。因为它接缝@Transaction
在我的TeamService
课上当时还没有开始。
然后当代码进入该getOwnTeam()
方法时,将启动一个新事务 [1]。但是在那里我不能再懒加载用户的团队了。[2]
我如何为我的用户和团队建模,以便
- 团队数据仅在必要时加载
- 必要时我可以手动加载数据
解决方案
如果您需要不同的负载启动,您可以使用:
- 查询时的原生sql
- jpql 与 join fetch 之类的结构
- 实体图 ( https://www.baeldung.com/jpa-entity-graph ) 使用这种方式加载的主要好处是对数据库的单个请求。您可以阅读更多https://thorben-janssen.com/lazyinitializationexception/
您的对象处于分离状态 - 例如,这是 LazyInitializationException 的原因(您将其移动到其他状态以加载您的对象)
entityManager.merge(deatachedEntity);
推荐阅读
- python - 如何从熊猫数据框列中删除字符串值?
- sql - pandas read_sql 将 NULL 导入为 0
- r - 为什么在 ggplot2 中运行相同的注释函数对其他人有用但对我抛出错误(审美长度)?
- netsuite - 在 NetSuite 保存的搜索中提取子字符串
- php - 今年每月的查询计数 - Laravel 5.8
- sql-server - 将 XML 元素转换为 T-SQL 中的属性
- python - 在 Django 中,为什么反向函数将元组作为参数传递?
- java - 在 Java 中制作具有不同播放速度的声音文件
- java - JavaFX 3D围绕纬度旋转相机Y
- python - 必须通过只有布尔值错误的数据框?