spring data Jpa 多对多懒加载、和shiro整合踩坑日记
简介
对自己的博客系统进行重新整合,具体整合内容,对于用户登录注册的模块采用shiro框架,对关键代码进行改变后:
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
User currentUser = (User) SecurityUtils.getSubject().getSession().getAttribute("user");
String userName=currentUser.getUserName();
User user = userService.getUserByUserName(userName);
Long userId = user.getId();
// 获取用户拥有的角色
List<Role> roles = userService.getUserById(userId).getRoles();
log.info("[{}] roles list",roles);
List<String> roleNames = new ArrayList<>();
roles.forEach(role -> roleNames.add(role.getRoleName()));
log.info("[{}] roles list name",roles);
// 获取用户拥有的权限
List<Permission> permissions = new ArrayList<>();
roles.forEach(role -> permissions.addAll(role.getPermissionList()));
Set<String> permissionNames = new HashSet<>();
permissions.forEach(permission -> permissionNames.add(permission.getPermissionName()));
authorizationInfo.addRoles(roleNames);
authorizationInfo.addStringPermissions(permissionNames);
return authorizationInfo;
}
由于数据库采用的是springdatajpa,所以出现了懒加载问题。
报错信息:failed to lazily initialize a collection of role,但是如果更改成EAGE后,又会出现错误,什么session啥的。具体忘了如何解决了。
出现懒加载问题一般解决方案:
-
使用set集合代替list集合
-
两端都加上EAGER注解
-
加上@Fetch(FetchMode.SUBSELECT)
针对报错信息:
[PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags:以上
但是更改后,到shiro后,会不断循环roleList和perssionList,这时候,必须要阻止这种嵌套循环,出现这种错误的原因就是在于你的Role和User类中出现了toString方法的嵌套,导致栈溢出。解决就是删除toString方法中引起循环的字段,比如在Role中有UserList的存在,必须要把UserList进行删除,否则会出现栈溢出。
post代码:
User类:一个用户有多个角色,
package com.yamon.po;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.util.*;
/**
* @Created by Intellij IDEA.
* @author: 陈亚萌
* @Date: 2019/12/15
*/
@Setter
@Getter
@Entity
@Table(name = "t_user")
public class User {
@Id
@GeneratedValue
private Long id;
private String nickName;
private String userName;
private String password;
private String email;
private String avatar;
private String registerMethod;
private Integer type;
/**
* 地点
*/
private String province;
private String city;
private String district;
/**
* 职业
*/
private String job;
/**
* 用户电话
*/
private String telephone;
/**
* 用户的简单介绍,可以为空
*/
private String shortMessage;
private String token;
@Temporal(TemporalType.TIMESTAMP)
private Date createTime;
@Temporal(TemporalType.TIMESTAMP)
private Date updateTime;
/**
* 最近一次修改密码的时间
*/
@Temporal(TemporalType.TIMESTAMP)
private Date updatePwTime;
@OneToMany(mappedBy = "user",fetch = FetchType.EAGER)
private Set<Blog> blogs=new HashSet<>();
/**
* 用户的头像文件存放处
*/
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "file_id",referencedColumnName = "id")
private FileCommon fileCommon;
/**
* 盐值,用于shiro框架
*/
private String salt;
/**
* 用户收藏的博客
*/
@ManyToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
@JoinTable(name = "like_user_blog",joinColumns = {@JoinColumn(name = "user_id",referencedColumnName = "id")},
inverseJoinColumns = {@JoinColumn(name = "blog_id",referencedColumnName = "id")}
)
private Set<Blog> likeBlogs = new HashSet<>();
/**
* 一个用户拥有多个角色 多对多
*/
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "t_user_role",joinColumns = {@JoinColumn(name = "user_id",referencedColumnName = "id")},
inverseJoinColumns = {@JoinColumn(name = "role_id",referencedColumnName = "id")}
)
private List<Role> roles = new ArrayList<>();
public User(){
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", nickName='" + nickName + '\'' +
", userName='" + userName + '\'' +
", password='" + password + '\'' +
", email='" + email + '\'' +
", avatar='" + avatar + '\'' +
", registerMethod='" + registerMethod + '\'' +
", type=" + type +
", province='" + province + '\'' +
", city='" + city + '\'' +
", district='" + district + '\'' +
", job='" + job + '\'' +
", salt='" + salt + '\'' +
", telephone='" + telephone + '\'' +
", shortMessage='" + shortMessage + '\'' +
", token='" + token + '\'' +
", createTime=" + createTime +
", updateTime=" + updateTime +
", updatePwTime=" + updatePwTime +
", blogs=" + blogs +
", roles=" + roles +
", fileCommon=" + fileCommon +
'}';
}
}
Role类:一个角色对应多个用户
package com.yamon.po;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
/**
* @Created by Intellij IDEA.
* @author: 陈亚萌
* @Date: 2020/2/20
*/
@Setter
@Getter
@Entity
@Table(name = "t_role")
public class Role {
/**
* 角色id
*/
@Id
@GeneratedValue
private Long id;
/**
* 角色名称 : visitor 游客
* user : 用户
* admin: 管理员、
* value:visitor
* user
* admin
*/
private String roleName;
/**
* 对应于roleName 的描述
* value: 游客、用户、管理员
*/
private String roleDesc;
/**
* 角色所拥有的权利:增删改查 一对多
*/
@OneToMany(mappedBy = "roles",fetch = FetchType.EAGER)
private List<Permission> permissionList;
/**
* 一个角色拥有多个用户
*
*/
@ManyToMany(mappedBy = "roles",fetch=FetchType.EAGER)
@Fetch(FetchMode.SUBSELECT)
private List<User> userList = new ArrayList<>();
@Override
public String toString() {
return "Role{" +
"id=" + id +
", roleName='" + roleName + '\'' +
", roleDesc='" + roleDesc + '\'' +
", permissionList=" + permissionList +
'}';
}
}
Permission类:一个角色有多个权限,一个权限能被多个角色拥有
package com.yamon.po;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
/**
* @Created by Intellij IDEA.
* @author: 陈亚萌
* @Date: 2020/2/20
*/
@Setter
@Getter
@Entity
@Table(name = "t_permission")
public class Permission {
/**
* 自增id
*/
@Id
@GeneratedValue
private Long id;
/**
* 赋予权力:
* user:get : 查询用户
* user:insert: 添加用户
* user:update: 更新用户
* user:delete: 删除用户
* value:1. user:get
* 2. user:insert
* 3. user:update
* 4. user:delete
*/
private String permissionName;
/**
* value:查询用户
* 2. 添加用户
* 更新用户
* 删除用户
*/
private String permissionDesc;
/**
*
*/
@ManyToOne(fetch = FetchType.EAGER)
private Role roles ;
@Override
public String toString() {
return "Permission{" +
"id=" + id +
", permissionName='" + permissionName + '\'' +
", permissionDesc='" + permissionDesc + '\'' +
'}';
}
}
具体看toString方法和@ManyToMany注解阻止懒加载
参考博客
解决问题:failed to lazily initialize a collection of role异常解决
Spring Data JPA 之 一对一,一对多,多对多 关系映射
[SpringData JPA一对多多对一多对多关联](https://www.cnblogs.com/mayuan01/p/12006673.html)
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:
Hibernate:cannot simultaneously fetch multiple bags 解决方案
上面的博客总有一个适合你。