如何在ManyToMany中使用FetchType.LAZY?

时间:2017-10-18 13:06:55

标签: java spring hibernate spring-boot

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

类角色:

@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:懒得初始化   角色集合:User.roles,无法初始化代理 - 无会话

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

  

java.lang.StackOverflowError:null

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

如何解决此问题?我在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;
        }
    }

    ...

2 个答案:

答案 0 :(得分:2)

Hibernate已经告诉你原因:

  

org.hibernate.LazyInitializationException:懒得初始化   角色集合:User.roles,无法初始化代理 - 没有   会话

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

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

@Transactional是你的朋友。 @Transactional注释将创建具有特定范围的休眠会话(例如,方法)

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

这将有效,因为hibernate会为此方法的范围保持相同的会话。

答案 1 :(得分:1)

使用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);