You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Security表单登录触发LazyInitializationException问题求助

解决Spring Security表单登录的LazyInitializationException问题

核心原因

你遇到的问题本质是:Spring Security认证流程中,UserDetailsService加载用户后,事务已结束,此时调用getAuthorities()访问懒加载的roles集合时,Hibernate Session已经关闭,导致无法初始化代理对象。你在User类上加的@Transactional无效,因为这个注解无法覆盖Spring Security的认证查询流程;而注册流程能正常访问是因为注册操作全程处于事务上下文内。

具体解决方案

方案1:在UserDetailsService的查询逻辑中确保事务覆盖并加载关联集合

  • 在UserDetailsService实现类的loadUserByUsername方法上添加@Transactional注解,让用户查询及后续权限集合的访问处于同一事务中:
@Service
public class CustomUserDetailsService implements UserDetailsService {
    @Autowired
    private UserRepository userRepository;

    @Override
    @Transactional
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("User not found"));
        // 主动触发roles集合加载,避免后续懒加载报错
        user.getRoles().size();
        return user;
    }
}
  • 更高效的方式是用fetch join的JPQL查询,直接在查询时加载roles集合,从根源避免懒加载:
// 在UserRepository中定义查询方法
@Query("SELECT u FROM User u JOIN FETCH u.roles WHERE u.username = :username")
Optional<User> findByUsernameWithRoles(@Param("username") String username);

之后在loadUserByUsername中调用这个方法即可。

方案2:修改实体关联的FetchType为EAGER

直接将User类中roles字段的懒加载改为立即加载:

@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
        name = "user_roles",
        joinColumns = @JoinColumn(name = "user_id"),
        inverseJoinColumns = @JoinColumn(name = "role_id")
)
private Set<Role> roles = new HashSet<>();

注意:这种方式会在每次查询User时都加载roles集合,若roles数据量大或用户查询频繁,可能存在性能损耗,需根据业务场景评估。

方案3:开启Open Session In View(不推荐生产环境)

可以通过配置spring.jpa.open-in-view=true开启OSIV模式,让Hibernate Session在请求全程保持打开。但这种方式容易引发内存泄漏和性能问题,仅适合小型项目或调试场景。

内容的提问来源于stack exchange,提问作者Batuhan Kertmen Student

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 20:38:13