tinguo002的gravatar头像
tinguo002 2017-12-31 14:25:10
hibernate三表以上迫切左外连接

为什么要使用迫切左外连接?

迫切左外连接:解决hibernate n+1次查询问题。

二表的迫切左外连接语句修改:实现三表及以上的迫切左外连接。

 

场景描述:

有五张表:角色表、菜单表、功能表、角色-菜单表、角色-功能表

角色表有二个外键(menuid和functionid)

菜单表有一个外键(functionid)

角色表里的二个外键,使用 ManyToMany、ManyToMany

菜单表里的一个外键,使用 OneToMany

hibernate做完关联之后,查询一切正常,但是打印出来的SQL 语句非常多。类似这样:

菜单表有10条记录,我加载菜单列表,会产生11条SQL语句。查询菜单表一条记录,10个菜单实例,每个实例都查询一次功能表。

这是一个追求完美的程序员所不允许的。

下面讲述如何去除多余的SQL查询。

 

源码:

包括:角色类、菜单类、功能类、二表左外迫切连接语句、三表左外迫切连接语句、sql打印

角色类

package basic.basicBean;

import javax.persistence.*;
import java.util.Set;


@Entity
@Table(name = "role", catalog="cms2017banksvr")
public class Role {

    private long id;
    private String rolename;
    private String rolenumber;
    private String info;
    private Set<Menu> menuSet;
    private Set<Function> functionSet;

    @Id
    @Column(name = "id")
    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }

    @Basic
    @Column(name = "rolename")
    public String getRolename() {
        return rolename;
    }

    public void setRolename(String rolename) {
        this.rolename = rolename;
    }
    @Basic
    @Column(name = "rolenumber")
    public String getRolenumber() {
        return rolenumber;
    }

    public void setRolenumber(String rolenumber) {
        this.rolenumber = rolenumber;
    }
    @Basic
    @Column(name = "info")
    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }

    @ManyToMany(cascade = {CascadeType.MERGE,CascadeType.REFRESH},fetch=FetchType.EAGER)
    @JoinTable(name="rolemenu",joinColumns = { @JoinColumn(name ="roleid" )},inverseJoinColumns = { @JoinColumn(name = "menuid") })
    public Set<Menu> getMenuSet() {
        return menuSet;
    }
    public void setMenuSet(Set<Menu> menuSet) {
        this.menuSet = menuSet;
    }
    
    @ManyToMany(cascade = {CascadeType.MERGE,CascadeType.REFRESH},fetch=FetchType.EAGER)
    @JoinTable(name="rolefunction",joinColumns = { @JoinColumn(name ="roleid" )},inverseJoinColumns = { @JoinColumn(name = "functionid") })
    public Set<Function> getFunctionSet() {
        return functionSet;
    }

    public void setFunctionSet(Set<Function> functionSet) {
        this.functionSet = functionSet;
    }
}

 

菜单类

package basic.basicBean;

import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;


@Entity
@Table(name = "menu", catalog="cms2017banksvr")
public class Menu {

    private long id;
    private String name;
    private int orderNum;
    private Long parentid;
    private String url;
    private String iconcls;
    private String selectedurl;
    private String info;
    private List<Function> functionList;

    @Id
    @Column(name = "id")
    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }

    @Basic
    @Column(name = "name")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    @Basic
    @Column(name = "orderNum")
    public int getOrderNum() {
        return orderNum;
    }

    public void setOrderNum(int orderNum) {
        this.orderNum = orderNum;
    }
    @Basic
    @Column(name = "parentid")
    public Long getParentid() {
        return parentid;
    }

    public void setParentid(Long parentid) {
        this.parentid = parentid;
    }
    @Basic
    @Column(name = "url")
    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
    @Basic
    @Column(name = "iconcls")
    public String getIconcls() {
        return iconcls;
    }

    public void setIconcls(String iconcls) {
        this.iconcls = iconcls;
    }
    @Basic
    @Column(name = "selectedurl")
    public String getSelectedurl() {
        return selectedurl;
    }

    public void setSelectedurl(String selectedurl) {
        this.selectedurl = selectedurl;
    }
    @Basic
    @Column(name = "info")
    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }

    @OneToMany(cascade = {CascadeType.MERGE,CascadeType.REFRESH})
    @JoinColumn(name="menuid")
    public List<Function> getFunctionList() {
        return functionList;
    }

    public void setFunctionList(List<Function> functionList) {
        this.functionList = functionList;
    }
}

 

功能类

package basic.basicBean;

import javax.persistence.*;


@Entity
@Table(name = "function", catalog="cms2017banksvr")
public class Function {

    private long id;
    private String name;
    private int orderNum;
    private String url;
    private String img;
    private String info;
    private Long menuid;

    @Id
    @Column(name = "id")
    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }

    @Basic
    @Column(name = "name")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    @Basic
    @Column(name = "orderNum")
    public int getOrderNum() {
        return orderNum;
    }

    public void setOrderNum(int orderNum) {
        this.orderNum = orderNum;
    }
    @Basic
    @Column(name = "url")
    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
    @Basic
    @Column(name = "img")
    public String getImg() {
        return img;
    }

    public void setImg(String img) {
        this.img = img;
    }
    @Basic
    @Column(name = "info")
    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }

    @Basic
    @Column(name = "menuid")
    public Long getMenuid() {
        return menuid;
    }

    public void setMenuid(Long menuid) {
        this.menuid = menuid;
    }
}

 

二表左外迫切连接源码

hql = "SELECT distinct(m) FROM Menu m left outer join fetch m.functionList f  order by m.orderNum asc";//distinct 去除重复记录
ArrayList menuList = basicService.queryList(hql,null);

调用后的sql打印

Hibernate: select menu0_.id as id3_0_, functionli1_.id as id2_1_, menu0_.iconcls as iconcls3_0_, menu0_.info as info3_0_, menu0_.name as name3_0_, menu0_.orderNum as orderNum3_0_, menu0_.parentid as parentid3_0_, menu0_.selectedurl as selected7_3_0_, menu0_.url as url3_0_, functionli1_.img as img2_1_, functionli1_.info as info2_1_, functionli1_.menuid as menuid2_1_, functionli1_.name as name2_1_, functionli1_.orderNum as orderNum2_1_, functionli1_.url as url2_1_, functionli1_.menuid as menuid3_0__, functionli1_.id as id0__ from cms2017banksvr.menu menu0_ left outer join cms2017banksvr.function functionli1_ on menu0_.id=functionli1_.menuid order by menu0_.orderNum asc

 

三表左外迫切连接源码

String hql = "SELECT distinct(r) FROM Role r left outer join fetch r.functionSet f left outer join fetch  r.menuSet m  order by r.id asc";//distinct去除重复记录
ArrayList roleList = basicService.queryList(hql,null);

调用后的sql打印

Hibernate: select role0_.id as id4_0_, function2_.id as id2_1_, menu4_.id as id3_2_, role0_.info as info4_0_, role0_.rolename as rolename4_0_, role0_.rolenumber as rolenumber4_0_, function2_.img as img2_1_, function2_.info as info2_1_, function2_.menuid as menuid2_1_, function2_.name as name2_1_, function2_.orderNum as orderNum2_1_, function2_.url as url2_1_, functionse1_.roleid as roleid4_0__, functionse1_.functionid as functionid0__, menu4_.iconcls as iconcls3_2_, menu4_.info as info3_2_, menu4_.name as name3_2_, menu4_.orderNum as orderNum3_2_, menu4_.parentid as parentid3_2_, menu4_.selectedurl as selected7_3_2_, menu4_.url as url3_2_, menuset3_.roleid as roleid4_1__, menuset3_.menuid as menuid1__ from cms2017banksvr.role role0_ left outer join rolefunction functionse1_ on role0_.id=functionse1_.roleid left outer join cms2017banksvr.function function2_ on functionse1_.functionid=function2_.id left outer join rolemenu menuset3_ on role0_.id=menuset3_.roleid left outer join cms2017banksvr.menu menu4_ on menuset3_.menuid=menu4_.id order by role0_.id asc

 

希望能够帮助大家解决sql执行 n+1 的问题。

 

hibernate  ManyToMany中的 cascade的配置我还未理解,大家不要照抄我的配置哈。如果有理解比较透的希望能够留言解惑一下。

 

ps:我在前进的道路上摸索,走在我前面的、走在我后面的同志,希望都能搭把手,让这条路更宽。


打赏

已有1人打赏

最代码官方的gravatar头像
最近浏览
水光浮藻  LV6 2021年4月12日
859684581 2020年3月10日
暂无贡献等级
一念之插  LV1 2020年2月27日
youwuzuichen  LV10 2019年10月4日
laoxu99 2019年8月4日
暂无贡献等级
chen_xian 2018年11月6日
暂无贡献等级
ronnie0507  LV8 2018年6月15日
liangxiang  LV6 2018年5月23日
smfx1314  LV8 2018年1月19日
LiangJiaWen  LV5 2018年1月17日
顶部 客服 微信二维码 底部
>扫描二维码关注最代码为好友扫描二维码关注最代码为好友