如何在ManyToMany中使用FetchType.LAZY?

qfe3c7zg  于 2022-10-04  发布在  Spring
关注(0)|答案(3)|浏览(160)

我有两个具有多对多关系的实体。

课堂角色:

@ManyToMany(mappedBy = "roles")
private Set<User> users = new HashSet<>();

和班级用户:

@ManyToMany
@JoinTable(name = "role_user", joinColumns = @JoinColumn(name = "user_id"),
        inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles = new HashSet<>();

我得到了一个例外:

Org.hibernate.LazyInitializationException:延迟初始化Role的集合失败:User.Roles,无法初始化代理-没有会话

当我添加fetch = FetchType.EAGER时,我得到另一个异常:

Java.lang.StackOverflow错误:空

并在角色和用户之间循环。

我如何才能解决这个问题?我在Stackoverflow上看到了类似的问题,但我没有找到真正有效的解决方案。

UPD:抛出异常的位置:

@Service
public class UserAuthenticationProvider implements AuthenticationProvider {
    ...

    @Override
    @Transactional
    public Authentication authenticate(final Authentication authentication) {
        final String login = authentication.getName();
        final String password = authentication.getCredentials().toString();

        final User user = userRepository.findByLogin(login);
        if (user != null && passwordEncoder.matches(password, user.getPassword())) {
            return new UsernamePasswordAuthenticationToken(login, password,
                    user.getRoles()); // problem here
        } else {
            return null;
        }
    }

    ...
yptwkmov

yptwkmov1#

Hibernate已经告诉你原因了:
Org.hibernate.LazyInitializationException:延迟初始化Role的集合失败:User.Roles,无法初始化代理-没有会话

public List<Role> getRolesForUserId(int id){
    UserEntity user = userRepository.findUserById(1)
    user.getRoles()
}

这将导致异常,因为您试图在没有活动的Hibernate会话的情况下获取延迟获取的用户角色。

@Transactional是你的朋友。@Transactional注解将创建具有特定作用域(例如,方法)的休眠会话

@Transactional 
public List<Role> getRolesForUserId(int id){
    UserEntity user = userRepository.findUserById(1)
    user.getRoles()
}

这是可行的,因为Hibernate在此方法的作用域中保持相同的会话打开。

j2qf4p5b

j2qf4p5b2#

使用Spring JPA,在您的JPQL上尝试关键字“Join Fetch”,您可以处理延迟初始化异常。示例

@Query("SELECT u FROM User u JOIN FETCH u.roles r WHERE r.roleId = :roleId AND u.userId=:userId")
User findUserById(@Param("roleId") String roleId, @Param("userId") String userId);
8aqjt8rx

8aqjt8rx3#

@Transactional似乎不适用于AuthenticationProvider的重写方法。我应该创建一个单独的服务来处理这个问题。

这里有一个类似的答案:https://stackoverflow.com/a/23652569/8253837

相关问题