Hibernate @ManyToMany delete relation

場景

假設有倆個實體用戶和專業課(關係:多對多)git

現需求用戶能夠新增編輯專業課,但在專業課模塊中一樣能夠新增用戶和編輯用戶github

實體

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:app

@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映射關係是由一方維護,因此須要後臺單獨處理中間表中的數據測試

實現以下:
image.pngspa

在更新中把中間表相關數據先移出,而後在從新創建關係,以下:hibernate

image.png

將新的數據,保存到中間表中。在此使專業課和用戶從新創建新的關係code

在新增時只需save時在調用updateUsersOfCourse(Course course)這個方法就能夠blog

這種實現方式看起來比較笨拙,潘老師提示, Hibernate不會這麼傻,須要這麼麻煩,確定有新的實現方式

新的實現

使用Hibernate的關聯刪除,去除手動操做中間表的代碼,看起來更簡潔,更新更容易理解文檔

image.png

修改實體 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:

image.png

B:

image.png

C:

image.png

源碼地址 github

使用Postman向後臺發送請求,執行更新操做,獲得SQl語句,以下:

上述新方法生成的SQL語句:

image.png

普通的方式mappedBy生成的SQL語句:

image.png

發現普通的方式 mappedBy生成的 SQL語句比較多,多的是更新時操做中間表 SQL,爲數據庫增長了無形的壓力。
相關文章
相關標籤/搜索