2017-10-18 153 views
1

我有两个具有多对多关系的实体。如何在ManyToMany中使用FetchType.LAZY?

类角色

@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: failed to lazily initialize a collection of role: User.roles, could not initialize proxy - no Session

当我添加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; 
     } 
    } 

    ... 
+0

我不相信问题出现在您提交的声明中。请提供一份[mcve],可以复制您报告的一项或两项例外情况。 –

回答

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); 
2

的Hibernate已经告诉你为什么:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: User.roles, could not initialize proxy - no Session

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会话,因为Hibernate将保持打开此方法的范围相同的会话。

+0

它没有帮助我。我添加了@ Transactional注解和@EnableTransactionManagement,但没有任何改变。如果我用bean配置'HibernateTransactionManager'和'SessionFactory',我有一个例外情况,名为'entityManagerFactory'的bean无法找到。' 我还可以尝试什么? –

+0

我同意@ Herr的解决方案。好像你的收藏脱离了会议。在模型类中也可以更新注释。在类Role中,更新注解'@ManyToMany(fetch = FetchType.LAZY,mappedBy =“roles”)'并在类中将用户更新为@ManyToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL)。 – Neero

+0

我更新了注释,但它没有帮助。我尝试使用这个答案:https://stackoverflow.com/a/30884155/8253837并添加了@ @PersistenceContext private EntityManager em;'在类中使用@ Transactional'方法,现在我有'java.lang.StackOverflowError'例外。 另外我的UserRepository扩展CrudRepository,如果它很重要;但是我为使用UserRepository的'@ Transactional'方法创建了separeted类。 –

相关问题