spring data jpa 多表操作之多对多
拉大锯
发表于
2020-03-19 23:28
1654
多对多
SpringData
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的例子来说明一下。