为什么Spring引导“未能懒惰地初始化一个角色集合”通过Eager获取类型解决?

为什么Spring引导“未能懒惰地初始化一个角色集合”通过Eager获取类型解决?

问题描述:

我在写一个简单的Spring引导应用程序。为什么Spring引导“未能懒惰地初始化一个角色集合”通过Eager获取类型解决?

对于身份验证部分,我实现了一个自定义的UserDetails。当我做出登录端点的请求我得到这个异常:

Authentication Failed: failed to lazily initialize a collection of role: com.boot.cut_costs.config.security.CustomUserDetails.roles, could not initialize proxy - no Session

CustomUserDetails.java

@Entity 
@Table(name="ACCOUNT_USER") 
public class CustomUserDetails implements UserDetails { 

    private static final long serialVersionUID = 1L; 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(name = "USER_ID") 
    private long id; 

    @NotBlank 
    @Column(name = "USERNAME") 
    private String username; 

    @NotBlank 
    @Column(name = "PASSWORD") 
    private String password; 

    @Column(name = "LOCKED") 
    private boolean locked; 

    @ManyToMany(cascade=CascadeType.ALL) 
    @JoinTable(name = "USER_ROLE", 
       joinColumns = @JoinColumn(name = "USER_ID"), 
       inverseJoinColumns = @JoinColumn(name = "ROLE_ID")) 
    private Set<CustomRole> roles; 

    public CustomUserDetails(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<GrantedAuthority> authorities) { // jpa only 
     this.setUsername(username); 
     this.setPassword(password); 
     this.roles = new HashSet<CustomRole>(); 
     for (GrantedAuthority authority: authorities) { 
      roles.add(new CustomRole(authority.getAuthority())); 
     } 
    } 

    public CustomUserDetails() { // jpa only 
    } 

    @Override 
    public String getPassword() { 
     return password; 
    } 

    public void setPassword(String password) { 
     this.password = password; 
    } 

    @Override 
    public String getUsername() { 
     return username; 
    } 

    public void setUsername(String username) { 
     this.username = username; 
    } 

    public Set<CustomRole> getRoles() { 
     return roles; 
    } 

    public void setRoles(Set<CustomRole> roles) { 
     this.roles = roles; 
    } 

    @Override 
    public Collection<GrantedAuthority> getAuthorities() { 
     ArrayList<String> authoritiesList = new ArrayList<String>(); 
     for (CustomRole role: roles) { 
      authoritiesList.add(role.getRole()); 
     } 
     return AuthorityUtils.commaSeparatedStringToAuthorityList(String.join(",", authoritiesList)); 
    } 
    //Some more getters and setters ... 

} 

CustomRole.java

@Entity 
@Table(name="ACCOUNT_ROLE") 
public class CustomRole { 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(name="ROLE_ID") 
    private long id; 

    @Column(name="ROLE") 
    private String role; 

    public long getId() { 
     return id; 
    } 

    //delete if not necessary 
    public void setId(long id) { 
     this.id = id; 
    } 

    public String getRole() { 
     return role; 
    } 

    public void setRole(String role) { 
     this.role = role; 
    } 

    public CustomRole() {} //for jpa 

    public CustomRole(String role) { 
     this.role = role; 
    } 
} 

当我做出ManyToMany注释的获取类型Eager,有用。

我在SO中读过,这不是一个好习惯。首先,我想知道为什么?第二,我想知道什么是好的做法?我在这里混合服务层和DAO吗?

+0

我可能说错了(如果是这种情况,我希望能纠正)但我猜你在尝试访问该服务之前就结束了该事务懒惰的收集,因此没有加载它。急切的模式明显地解决了这个问题,但我想一个更明智的方法是让服务方法在同一事务中加载集合,以保持实体的惰性行为,并在需要时通过服务获取集合。 –

当您使用懒惰加载用户无需角色和角色将只收取当您使用它们

在这里你使用春季安全,你应该把渴望当你调用CustomUserDetails加载的所有角色, 在一般情况下使用Eager并不是一个好习惯,因为你加载了许多不需要它们的细节

+0

有使用Eager获取类型的更好的解决方案吗?例如通过改变设计? –

+0

你可以在这里使用Eager,因为你没有大量的角色,所以你可以使用Eager没有问题,在我的项目中,我使用EAGER像这样'@ManyToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER) \t @JoinTable(名称= “user_roles”, \t \t joinColumns = {@JoinColumn(名称= “USER_ID”,referencedColumnName = “ID”)}, \t \t inverseJoinColumns = {@JoinColumn(名称= “ROLE_ID”,referencedColumnName =” ID“)} \t) \t私人列表角色; –