zl程序教程

您现在的位置是:首页 >  后端

当前栏目

springboot jpa 至 many to many的级联关系

SpringBoot to 关系 jpa 级联 many
2023-09-27 14:22:12 时间

一.说明

 角色和菜单时多对多关系
*角色是多方;菜单也是多方;

在roles:

@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
//@JoinTable:映射中间表
//joinColumns:当前表中的主键所关联的中间表中的外键字段
//inverseJoinColumns:关联menus表的外键叫什么
@JoinTable(name="tb_roles_menus",joinColumns=@JoinColumn(name="role_id"),inverseJoinColumns=@JoinColumn(name="caidan_id"))
private Set<Menus> menusSet = new HashSet<Menus>();

在meuns:

@ManyToMany(mappedBy="menusSet",cascade=CascadeType.ALL )
private Set<Roles> rolesSet = new HashSet<>();

加载树形结构,使用关闭懒加载fetch=FetchType.EAGER

在数据库中取值的时候,如果使用懒加载,就会只取出一层节点的数据,然后关闭session,这样再去取下一层级的数据的时候就会报出错误:session is closed

如果是EAGER,那么表示取出这条数据时,它关联的数据也同时取出放入内存中

如果是LAZY,那么取出这条数据时,它关联的数据并不取出来,在同一个session中,什么时候要用,就什么时候取(再次访问数据库)。

但是,在session外,就不能再取了。用EAGER时,因为在内存里,所以在session外也可以取。

二.新建工程

2.1 新建pom文件:

 <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13</version>
      <scope>test</scope>
    </dependency>
    <!-- springBoot的启动器 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- 添加junit环境的jar包 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    <!-- springBoot的启动器 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <!-- mysql -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!-- druid连接池 -->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.10</version>
    </dependency>
  </dependencies>

2.2 新建Menus文件:

package com.ljf.spring.boot.demo.jpa.relation.model;

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

/**
 * @ClassName: Menus
 * @Description:    角色和菜单时多对多关系
 *       角色是多方;菜单也是多方;
 *
 * @Author: liujianfu
 * @Date: 2020/08/30 17:39:24 
 * @Version: V1.0
 **/
@Entity
@Table(name="tb_menus")
public class Menus {
    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    @Column(name="menus_id")
    private Integer menusId;
    @Column(name="menus_name")
    private String menusName;
    @Column(name="menus_url")
    private String menusUrl;
    @Column(name="father_id")
    private Integer fatherId;
    @ManyToMany(mappedBy="menusSet",cascade=CascadeType.ALL )
    private Set<Roles> rolesSet = new HashSet<>();

    public Integer getMenusId() {
        return menusId;
    }

    public void setMenusId(Integer menusId) {
        this.menusId = menusId;
    }

    public String getMenusName() {
        return menusName;
    }

    public void setMenusName(String menusName) {
        this.menusName = menusName;
    }

    public String getMenusUrl() {
        return menusUrl;
    }

    public void setMenusUrl(String menusUrl) {
        this.menusUrl = menusUrl;
    }

    public Integer getFatherId() {
        return fatherId;
    }

    public void setFatherId(Integer fatherId) {
        this.fatherId = fatherId;
    }

    public Set<Roles> getRolesSet() {
        return rolesSet;
    }

    public void setRolesSet(Set<Roles> rolesSet) {
        this.rolesSet = rolesSet;
    }

}

2.3 新建Roles文件:

package com.ljf.spring.boot.demo.jpa.relation.model;

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

/**
 * @ClassName: Roles
 * @Description:       用户和角色是1:1关系 ;角色和用户是1:n关系;
 *  *                  角色是少的一方,所以配置@OneToMany
 * @Author: liujianfu
 * @Date: 2020/08/21 12:19:35
 * @Version: V1.0
 **/
@Entity
@Table(name="tb_roles")
public class Roles {
    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    @Column(name="role_id")
    private Integer roleId;
    @Column(name="role_name")
    private String roleName;
    @OneToMany(mappedBy="roles",cascade=CascadeType.ALL,fetch=FetchType.LAZY)  //见Users实体中的roles属性,要保持一致
    private Set<Users> usersSet = new HashSet<>();
    @ManyToMany(cascade=CascadeType.ALL)
    //@JoinTable:映射中间表
    //joinColumns:当前表中的主键所关联的中间表中的外键字段
    //inverseJoinColumns:关联menus表的外键叫什么
    @JoinTable(name="tb_roles_menus",joinColumns=@JoinColumn(name="role_id"),inverseJoinColumns=@JoinColumn(name="caidan_id"))
    private Set<Menus> menusSet = new HashSet<Menus>();
    public Integer getRoleId() {
        return roleId;
    }

    public void setRoleId(Integer roleId) {
        this.roleId = roleId;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public Set<Users> getUsersSet() {
        return usersSet;
    }

    public void setUsersSet(Set<Users> usersSet) {
        this.usersSet = usersSet;
    }

    public Set<Menus> getMenusSet() {
        return menusSet;
    }

    public void setMenusSet(Set<Menus> menusSet) {
        this.menusSet = menusSet;
    }
}

2.4 新建repository文件:

package com.ljf.spring.boot.demo.jpa.relation.repostory;

import com.ljf.spring.boot.demo.jpa.relation.model.Roles;
import com.ljf.spring.boot.demo.jpa.relation.model.Users;
import org.springframework.data.jpa.repository.JpaRepository;

public interface RoleMenusRespository extends JpaRepository<Roles,Integer> {
}

2.5 application配置文件:

#spring的配置mysql
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test_db?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
#ali
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

 

2.6 junit单元测试:

package com.ljf.spring.boot.demo.jpa.relation;

/**
 * @ClassName: ManyToManyTest
 * @Description: TODO
 * @Author: liujianfu
 * @Date: 2020/08/30 18:10:07 
 * @Version: V1.0
 **/

import com.ljf.spring.boot.demo.jpa.relation.model.Menus;
import com.ljf.spring.boot.demo.jpa.relation.model.Roles;
import com.ljf.spring.boot.demo.jpa.relation.model.Users;
import com.ljf.spring.boot.demo.jpa.relation.repostory.RoleMenusRespository;
import com.ljf.spring.boot.demo.jpa.relation.repostory.UserRespository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * SpringBoot测试类
 *@RunWith:启动器
 *SpringJUnit4ClassRunner.class:让junit与spring环境进行整合
 *
 *@SpringBootTest(classes={App.class}) 1,当前类为springBoot的测试类
 *@SpringBootTest(classes={App.class}) 2,加载SpringBoot启动类。启动springBoot
 *
 *junit与spring整合 @Contextconfiguartion("classpath:applicationContext.xml")
 */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes={App.class})   //springboot的启动类
public class ManyToManyTest {
    @Autowired
    RoleMenusRespository ur;
    /**
     *创建多对多的关系
     */
    @Test
    public void oneToManySave(){
        //创建角色对象
        Roles r = new Roles();
        r.setRoleName("项目经理");

        //创建菜单对象
        Menus menus = new Menus();
        menus.setMenusName("xxxx管理系统");
        menus.setMenusUrl("/uuuu");
        menus.setFatherId(0);

        Menus menus2 = new Menus();
        menus2.setMenusName("电商管理系统");
        menus2.setMenusUrl("/xmgl");
        menus2.setFatherId(0);
        //关联
        r.getMenusSet().add(menus);
        r.getMenusSet().add(menus2);
        menus.getRolesSet().add(r);
        menus2.getRolesSet().add(r);
        //保存
        ur.save(r);
    }
}

2.7 查看:

2.7 查询:需要在roles的@manytomany的加载策略进行修改,@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)

打印:

Hibernate: select roles0_.role_id as role_id1_1_0_, roles0_.role_name as role_nam2_1_0_, menusset1_.role_id as role_id1_2_1_, menus2_.menus_id as caidan_i2_2_1_, menus2_.menus_id as menus_id1_0_2_, menus2_.father_id as father_i2_0_2_, menus2_.menus_name as menus_na3_0_2_, menus2_.menus_url as menus_ur4_0_2_ from tb_roles roles0_ left outer join tb_roles_menus menusset1_ on roles0_.role_id=menusset1_.role_id left outer join tb_menus menus2_ on menusset1_.caidan_id=menus2_.menus_id where roles0_.role_id=?
项目经理
m:电商管理系统
m:xxxx管理系统