【发布时间】:2020-11-25 10:19:53
【问题描述】:
我正在使用 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;
}
}
@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);
}
}
这是我的两门课。一个用户实体和一个过滤器,将从身份验证对象创建用户。当调用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 时,它没有问题。
我试过的是:
-
@Transactional来自org.springframework.transaction.annotation.Transactional和javax.transaction.Transactional。但它完全没有改变。 - 将获取类型更改为
EAGER。这种方法有效,但不是我想做的。 - 在 application.properties 文件中将
enable_lazy_load_no_trans=true更改为 true。不推荐这种方法,所以我不会尝试。 - 在尝试修改惰性集合之前调用该方法。例如调用
user.getRoles().size();使其被初始化。但它不起作用。 - 调用
Hibernate.initialize(user.getRoles());来初始化集合。但它不起作用。
我想知道 Spring 为什么说 No Session,因为它确实为 userRepository.findByEmail(email) 和 userRepository.save(user) 创建了一个会话。
我可以手动创建一个实体管理器并使用它来获取/保留我的实体。但这不是我使用 Spring Data JPA 的目标。
【问题讨论】:
标签: java spring spring-boot hibernate jpa