Spring Data 未能延迟初始化角色集合,无法初始化代理 - 无会话

Ser*_*sky 0 java spring hibernate jpa spring-boot

我正在使用 Spring Boot 制作 API,但我似乎从未设法初始化惰性集合。对我有用的唯一解决方案是将其更改为热切,但这不是解决方案。

@Entity
@Getter
@Setter
@NoArgsConstructor
@Table(name = "user")
public class UserEntity {

    @Id
    @GeneratedValue
    private Long id;

    @Column(unique = true)
    String email;

    @ElementCollection(fetch = LAZY)
    List<String> roles = new ArrayList<>();

    public UserEntity(String email) {
        this.email = email;
    }
}
Run Code Online (Sandbox Code Playgroud)
@Order(Ordered.LOWEST_PRECEDENCE)
@Component
public class AuthFilter extends OncePerRequestFilter {

    Logger LOG = LoggerFactory.getLogger(AuthFilter.class);

    @Autowired
    UserRepository userRepository;

    @Override
    @Transactional
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if(authentication != null && authentication.isAuthenticated()){
            String email = authentication.getName();
            UserEntity user = userRepository.findByEmail(email).orElse(new UserEntity(email));
            user.getRoles().clear();
            user.getRoles().addAll(authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet()));
            userRepository.save(user);
        }
        filterChain.doFilter(request, response);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的两节课。一个用户实体和一个过滤器,将从一个身份验证对象创建用户。当这条线user.getRoles().clear();被调用时,我得到了著名的错误org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: ch.ciip.ressources.api.user.UserEntity.roles, could not initialize proxy - no Session

根据我的理解,Spring Data 会为每个惰性关系创建一个代理,并且只有在访问数据时才会获取数据。但是要访问它需要一个会话,显然,Spring 在访问代理时无法创建会话,但是,当我在存储库上调用 save 时,它​​没有问题。

我试过的是:

  • @Transactionalorg.springframework.transaction.annotation.Transactionaljavax.transaction.Transactional. 但它绝对没有改变。
  • 将获取类型更改为EAGER. 这种方法有效,但这不是我想要做的。
  • enable_lazy_load_no_trans=true在 application.properties 文件中更改为 true。这种方法不推荐,所以我不会尝试。
  • 在尝试修改它之前调用惰性集合上的方法。例如调用user.getRoles().size();所以它被初始化。但它不起作用。
  • 调用Hibernate.initialize(user.getRoles());以初始化集合。但它不起作用。

我想知道为什么 Spring 会说,No Session因为它确实userRepository.findByEmail(email)userRepository.save(user).

我可以手动创建一个实体管理器并使用它来获取/保留我的实体。但这不是我使用 Spring Data JPA 的目标。

And*_*cus 5

制作方法public,即:

@Override
@Transactional
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {

    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

    if(authentication != null && authentication.isAuthenticated()){
        String email = authentication.getName();
        UserEntity user = userRepository.findByEmail(email).orElse(new UserEntity(email));
        user.getRoles().clear();
        user.getRoles().addAll(authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet()));
        userRepository.save(user);
    }
    filterChain.doFilter(request, response);
}
Run Code Online (Sandbox Code Playgroud)