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啥的。具体忘了如何解决了。

出现懒加载问题一般解决方案:

  1. 使用set集合代替list集合

  2. 两端都加上EAGER注解

  3. 加上@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 解决方案

上面的博客总有一个适合你。

 posted on 2020-03-10 18:25  ben跑的换行符  阅读(741)  评论(0编辑  收藏  举报