场景
假设有俩个实体用户和专业课(关系:多对多)
现需求用户可以新增编辑专业课,但在专业课模块中同样可以新增用户和编辑用户
实体
Course:
@Entity
public class Course implements YunzhiEntity {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToMany(mappedBy = "courses")
private List<User> users;
public Course() {}
}
User:
@Entity
public class User implements YunzhiEntity {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
private String name;
@Column(nullable = false, unique = true)
private String username;
@Column(nullable = false)
private String password;
@ManyToMany
private List<Course> courses;
public User() {}
}
最初实现
思路
新增:新增比较简单,直接操作中间表把数据保存到中间表
更新:更新变向的理解也就是新增,所以就先把原来的删除在新增
由于mappedBy
映射关系是由一方维护,所以需要后台单独处理中间表中的数据
实现如下:
在更新中把中间表相关数据先移出,然后在重新建立关系,如下:
将新的数据,保存到中间表中。在此使专业课和用户重新建立新的关系
在新增时只需save
时在调用updateUsersOfCourse(Course course)
这个方法就可以
这种实现方式看起来比较笨拙,潘老师提示,Hibernate
不会这么傻,需要这么麻烦,肯定有新的实现方式
新的实现
使用Hibernate
的关联删除,去除手动操作中间表的代码,看起来更简洁,更新更容易理解
修改实体 Course实体与User实体,不使用由一方维护的mappedBy
来映射关系,如下:
Course:
@Entity
public class Course implements YunzhiEntity {
......
@ManyToMany(cascade ={CascadeType.REMOVE})
@JoinTable(name="User_Courses",joinColumns=@JoinColumn(name="Courses_id"),inverseJoinColumns=@JoinColumn(name="Users_id"))
@JsonView(users.class)
private List<User> users;
......
}
User:
@Entity
public class User implements YunzhiEntity {
......
@ManyToMany(cascade ={CascadeType.REMOVE})
@JoinTable(name="User_Courses",joinColumns=@JoinColumn(name="Users_id"),inverseJoinColumns=@JoinColumn(name="Courses_id"))
@JsonView(courses.class)
private List<Course> courses;
......
}
使用mappedBy
来建立俩实体间的关系,它是一方来维护的,就像 ‘A中有B或B中有A’,是单向的。所以直接使用cascade ={CascadeType.REMOVE}
级联删除,不好使;
向上述例子,‘A中有B,B中有A’,是双向的。“双向结构+双向维护外键”。这个双向维护外键,指无论是对course.users
还是user.courses
修改,保存后均会影响中间表的数据。
参考文档 stackoverflow
小测试
建立三个实体 A B C
A:B = ManyToMany(上述新方式)
A:C = ManyToMany(普通的方式mappedBy
)
同样执行多对多的更新操作。对比两个更新最终生成的SQl
语句有何不同。
A:
B:
C:
源码地址github
使用Postman
向后台发送请求,执行更新操作,得到SQl
语句,如下:
上述新方法生成的SQL
语句:
普通的方式mappedBy
生成的SQL
语句:
发现普通的方式mappedBy
生成的SQL
语句比较多,多的是更新时操作中间表SQL
,为数据库增加了无形的压力。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。