Hibernate:多對多刪除
阿新 • • 發佈:2018-12-18
案例:
書籍類(Book.java)和書籍類別(Category.java)
表結構:
t_hibernate_book表:
t_hibernate_category表:
t_hibernate_book_category表(中間表):
先建立多對多聯絡:
book類:
package com.zking.five.entity; import java.util.HashSet; import java.util.Set; public class Book { private Integer bookId; private String bookName; private Float price; //建立關聯 private Set<Category> categorys=new HashSet<Category>(); //強制立即載入 private Integer initCagetorys=0; public Integer getInitCagetorys() { return initCagetorys; } public void setInitCagetorys(Integer initCagetorys) { this.initCagetorys = initCagetorys; } public Set<Category> getCategorys() { return categorys; } public void setCategorys(Set<Category> categorys) { this.categorys = categorys; } public Integer getBookId() { return bookId; } public void setBookId(Integer bookId) { this.bookId = bookId; } public String getBookName() { return bookName; } public void setBookName(String bookName) { this.bookName = bookName; } public Float getPrice() { return price; } public void setPrice(Float price) { this.price = price; } }
category類:
package com.zking.five.entity; import java.util.HashSet; import java.util.Set; public class Category { private Integer categoryId; private String categoryName; //建立關聯 private Set<Book> books=new HashSet<Book>(); //強制立即載入 private Integer initBooks=0; public Integer getInitBooks() { return initBooks; } public void setInitBooks(Integer initBooks) { this.initBooks = initBooks; } public Set<Book> getBooks() { return books; } public void setBooks(Set<Book> books) { this.books = books; } public Integer getCategoryId() { return categoryId; } public void setCategoryId(Integer categoryId) { this.categoryId = categoryId; } public String getCategoryName() { return categoryName; } public void setCategoryName(String categoryName) { this.categoryName = categoryName; } }
配置檔案:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class table="t_hibernate_book" name="com.zking.five.entity.Book"> <id name="bookId" type="java.lang.Integer" column="book_id "> <generator class="increment"></generator> </id> <property name="bookName" type="java.lang.String" column="book_name "></property> <property name="price" type="java.lang.Float" column="price "></property> <!-- table:中間連線表 name="categorys":Book實體類裡的類屬性 --> <set table="t_hibernate_book_category" name="categorys" cascade="save-update" inverse="false"> <!-- one --> <key column="bid"></key> <!-- many --> <many-to-many column="cid" class="com.zking.five.entity.Category"></many-to-many> </set> </class> </hibernate-mapping>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class table="t_hibernate_category" name="com.zking.five.entity.Category">
<id name="categoryId" type="java.lang.Integer" column="category_id ">
<generator class="increment"></generator>
</id>
<property name="categoryName" type="java.lang.String" column="category_name "></property>
<set table="t_hibernate_book_category" name="books" cascade="save-update" inverse="true">
<key column="cid"></key>
<many-to-many column="bid" class="com.zking.five.entity.Book"></many-to-many>
</set>
</class>
</hibernate-mapping>
下面是測試結果:
1.如果cascade不管是主控方設定還是被控方設定,被設定為all,delete等與delete級聯刪除有關的屬性,兩端的以及中間表的記錄都會被刪除,這樣的需求一般比較少,但是如要這種需求,把cascade設定為all,delete即可刪除
2.只想刪除某一端和中間表的記錄。這種需求很常見,這時只要把cascade的設定是除與delete有關的任何級聯約束。
2.1:如果執行刪除的是主控方,只需要簡單的刪除這條記錄,級聯關係以及主控方的記錄同時刪除,但被控方的記錄仍然存在。因此只對主控方的多對多刪除是最簡單,直接的。程式碼如下:
/**
* 主控方刪除
* @param book
*/
public void delete(Book book) {
Session session = SessionFactoryUtils.getSession();
Transaction transaction = session.beginTransaction();
session.delete(book);
transaction.commit();
session.close();
}
2.2:如果你這個時候想直接刪除被控方,那麼很遺憾的告訴你,你只做到了一半,你只是簡單的把被控方的記錄刪除了,關聯關係仍然存在中間表裡,並且中間表裡的資料並沒有刪除掉,系統隨時會因為你的關聯訪問報外來鍵資訊的錯,程式碼如下:
public void delete(Category category) {
Session session = SessionFactoryUtils.getSession();
Transaction transaction = session.beginTransaction();
session.delete(category);
transaction.commit();
session.close();
}
2.3:如果想要刪除被控方和中間表的資料,就要先解除主控方和被控方的關聯關係,並且解除關係只能是主控方解除,被控方沒有這個能力,程式碼如下:
/**
* 被控方刪除:
* 1.先查詢出從表關係
* 2.被控方通過主控方來解除關聯關係
* 3.再去刪除被控方
* @param category
*/
public void delete(Category category) {
Session session = SessionFactoryUtils.getSession();
Transaction transaction = session.beginTransaction();
Category c = session.get(Category.class, category.getCategoryId());
for (Book b : c.getBooks()) {
b.getCategorys().remove(c); //主控方控制移除關聯
}
session.delete(c);
transaction.commit();
session.close();
}
Junit測試程式碼:
/**
* 主控方刪除
* 需求:刪除有關聯關係的一本書
* 刪除斗羅大陸這本書 目前這本書在中間表引用
*/
@Test
public void testDelete() {
book.setBookId(7);
this.bookDao.delete(book);
}
/**
* 被控方刪除
* 刪除有關聯關係的一個類別,包括該類別下的所有書籍
* 刪除玄幻這個類別 目前這個類別在中間表引用
*/
@Test
public void testDelete1() {
category.setCategoryId(4);
this.categoryDao.delete(category);
}
級聯刪除雖然可以用,但是卻有禁用級聯刪除的結論,因為有時用的級聯刪除會把所有資料刪除: