阳光沙滩
让学习编程变得简单
spring data jpa 多表操作之多对多
发表于 2020-03-19    阅读次数 117

spring data jpa 多表操作之多对多

前面我们学习了多表操作之一对多

Spring Data JPA多表关系之一对多

接下来我们看看多对多

什么情况下有多对多关系呢?

比如说用户和角色

一个用户可以有多个角色吧,比如说你是管理员,又是审查员,又是VIP用户,又是讲师,对吧。

一个角色也可以对应多个用户,比如说讲师,可以是张三,也可以是赵四呀!

创建表

CREATE TABLE `tb_user`(
	`user_id` INTEGER PRIMARY KEY AUTO_INCREMENT,
	`user_name` VARCHAR(32) NOT NULL,
	`user_gender` CHAR(1) NOT NULL,
	`user_age` INTEGER NOT NULL,
	`user_password` VARCHAR(32) NOT NULL
);


CREATE TABLE `tb_role` (
	`role_id` INTEGER PRIMARY KEY AUTO_INCREMENT,
	`role_name` VARCHAR(32) UNIQUE NOT NULL,
	`role_description` VARCHAR(32) NOT NULL
);


CREATE TABLE `tb_user_role`(
	`role_id` INTEGER NOT NULL,
	`user_id` INTEGER NOT NULL,
	CONSTRAINT `fk_tb_user_id` FOREIGN KEY (`user_id`) REFERENCES `tb_user` (`user_id`),
	CONSTRAINT `fk_tb_role_id` FOREIGN KEY (`role_id`) REFERENCES `tb_role` (`role_id`)
);

三张表吧,一个是用户表,一个是角色表

还有一张是中间表

创建bean类

User.java

package net.sunofbeach.security.domain;

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

@Entity
@Table(name = "tb_user")
public class User {

    @Id
    @Column(name = "user_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer userId;

    @Column(name = "user_name")
    private String userName;

    @Column(name = "user_gender")
    private String gender;

    @Column(name = "user_password")
    private String password;

    @Column(name = "user_age")
    private Integer age;

    /**
     * 1、声明表关系,多对多
     * 2、配置中间表
     */
    @ManyToMany(targetEntity = Role.class, fetch = FetchType.EAGER)
    @JoinTable(name = "tb_user_role",
            //current对象在中间表里的外键,name指的是中间表的字段,referencedColumnName指的是当前表的字段
            joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "user_id")},
            //target对象在中间表的外键,name指的是中间表的字段,referencedColumnName指的是当前表的字段
            inverseJoinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "role_id")})
    private Set<Role> roles = new HashSet<>();

    public Set<Role> getRoles() {
        return roles;
    }

    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}


Role.java

package net.sunofbeach.security.domain;


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

@Entity
@Table(name = "tb_role")
public class Role {

    @Id
    @Column(name = "role_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "role_name")
    private String roleName;

    @Column(name = "role_description")
    private String roleDescription;

    /**
     * 不需要维护外键,否则容易冲突
     */
    @ManyToMany(mappedBy = "roles")
    private Set<User> users = new HashSet<>();

    public Set<User> getUsers() {
        return users;
    }

    public void setUsers(Set<User> users) {
        this.users = users;
    }

    public String getRoleDescription() {
        return roleDescription;
    }

    public void setRoleDescription(String roleDescription) {
        this.roleDescription = roleDescription;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getRoleName() {
        return roleName;
    }

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

DAO自行创建啦,接下来我们就进行测试一下

测试

  • 测试添加角色

我在实际使用的时候,也是单独添加角色的,最好不要级联操作。删除数据容易出错。

    /**
     * 添加角色
     */
    @Test
    public void addRole() {
        Role role = new Role();
        role.setRoleName("admin");
        role.setRoleDescription("管理员用户");
        roleDao.save(role);
    }

添加结果:

图片描述

  • 添加用户

在添加用户的时候,我们先是查询到现有的角色,然后在创建用户的时候,关联起来。

    @Test
    public void testAdd() {
        User user = new User();
        user.setPassword("123456");
        user.setAge(15);
        user.setUserName("president");
        user.setGender("1");
        Role admin = roleDao.findOneByRoleName("admin");
        user.getRoles().add(admin);
        Role teacher = roleDao.findOneByRoleName("teacher");
        user.getRoles().add(teacher);
        userDao.save(user);
    }

我多添加几个用户的结果:

用户表

图片描述

中间表

图片描述

  • 查询测试

通常来说,我们要知道某一个用户,ta对应的角色

或者我们在后台编辑的时候,查看这个角色都有哪些用户

    @Test
    public void testListUser() {
        List<User> all = userDao.findAll();
        for (User user : all) {
            String userName = user.getUserName();
            StringBuffer sb = new StringBuffer("[");
            for (Role role : user.getRoles()) {
                String roleName = role.getRoleName();
                sb.append(roleName + ",");
            }
            sb.replace(sb.length() - 1, sb.length(), "");
            sb.append("]");
            System.out.println("user -- > " + userName + " role -- > " + sb.toString());
        }
    }

执行结果:

user -- > president role -- > [teacher,admin]
user -- > BillGates role -- > [register,teacher]
user -- > LarryPage role -- > [register]

查询角色,把对应的用户也弄出来

@Test
    public void testListRole() {
        List<Role> all = roleDao.findAll();
        for (Role role : all) {
            String roleName = role.getRoleName();
            StringBuffer sb = new StringBuffer("[");
            for (User user : role.getUsers()) {
                sb.append(user.getUserName());
                sb.append(",");
            }
            sb.replace(sb.length() - 1, sb.length(), "");
            sb.append("]");
            System.out.println("role -- > " + roleName + " uses -- > " + sb.toString());
        }
    }

执行结果

role -- > register uses -- > [LarryPage,BillGates]
role -- > teacher uses -- > [BillGates,president]
role -- > admin uses -- > [president]

通常来说,我们是在登录的时候,需要知道用户是什么角色。

所以,一般是前面的查询方式,不过呢,只是查一个用户罢了。

对应的角色也出来了,根据角色跟权限的关系,再决定这个用户是否要以访问该接口。

后期我们可以通过spring Security的例子来说明一下。