为什么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吗?
当您使用懒惰加载用户无需角色和角色将只收取当您使用它们
在这里你使用春季安全,你应该把渴望当你调用CustomUserDetails加载的所有角色, 在一般情况下使用Eager并不是一个好习惯,因为你加载了许多不需要它们的细节
有使用Eager获取类型的更好的解决方案吗?例如通过改变设计? –
你可以在这里使用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私人列表
我可能说错了(如果是这种情况,我希望能纠正)但我猜你在尝试访问该服务之前就结束了该事务懒惰的收集,因此没有加载它。急切的模式明显地解决了这个问题,但我想一个更明智的方法是让服务方法在同一事务中加载集合,以保持实体的惰性行为,并在需要时通过服务获取集合。 –