【发布时间】:2021-01-16 17:49:15
【问题描述】:
我有一个无状态的 REST 后端。所以没有 HTML 视图。只是 JSON 和 REST 端点。
使用 Json Web 令牌完成身份验证。客户端在每个请求中发送一个 JWT。
我的后端从这个 JWT 中的主题声明中获取用户的电子邮件。然后它从class LiquidoUserDetailsService implements UserDetailsService { ...}的数据库中加载UserModel
每个用户都是团队的一部分。但是团队是一个很大的实体,里面有很多信息。所以团队只会在必要时延迟加载:
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;
[...]
}
现在我有一个服务应该返回当前用户的团队:
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
}
现在我想我知道问题出在哪里了。但我还没有一个干净的解决方案。
我的 UserModel 已加载到 class LiquidoUserDetailsService implements UserDetailsService 中,但这很早就发生在过滤器中,当 HTTP 请求被处理时。因为它接缝了我的TeamService 课程中的@Transaction,那时还没有开始。
然后当代码进入getOwnTeam() 方法时,一个new 事务被启动[1]。但是在那里我不能再懒加载用户的团队了。 [2]
我如何为我的用户和团队建模,以便
- 团队数据仅在必要时加载
- 我可以在必要时手动加载数据
【问题讨论】:
-
您能确认 TransactionSynchronizationManager.isActualTransactionActive() 在 @Transactional 块中返回 true 吗?
-
另外,您是否有理由在该方法中使用@Transactional 注释?我认为没有必要
-
REST 控制器方法
getOwnTeam()上的@Transactional注释在那里,因为我认为,然后 UserModel 和延迟加载的 TeamModel 将成为该事务的一部分.显然这个假设是错误的。
标签: spring hibernate spring-data-jpa