今天分享hibernate框架的兩個關聯關系
多對多關系注意事項
- 一定要定義一個主控方
- 多對多刪除
- 主控方直接刪除
- 被控方先通過主控方解除多對多關系,再刪除被控方
- 禁用級聯刪除
- 關聯關系編輯,不需要直接操作橋接表,hibernate的主控方會自動維護
重點解析:
-
數據庫的多對多
-
數據庫中不能直接映射多對多
處理:創建一個橋接表(中間表),將一個多對多關系轉換成兩個一對多
-
hibernate的多對多
-
hibernate可以直接映射多對多關聯關系(看作兩個一對多)
一:一對多自關聯
- 設計數據庫
t_hibernate_sys_tree_node表
實體類
TreeNode類
package com.ht.four.entity; import java.util.HashSet; import java.util.Set; public class TreeNode{ private Integer nodeId; private String nodeName; private Integer treeNodeType; private Integer position; private String url; private TreeNode parent; private Set<TreeNode> children = new HashSet<TreeNode>(); private Integer initChildren = 0; //0懶加載 1.強制加載(子節點) 2.強制加載用戶 3.強制加載兩個 public Integer getNodeId() { return nodeId; } public void setNodeId(Integer nodeId) { this.nodeId = nodeId; } public String getNodeName() { return nodeName; } public void setNodeName(String nodeName) { this.nodeName = nodeName; } public Integer getTreeNodeType() { return treeNodeType; } public void setTreeNodeType(Integer treeNodeType) { this.treeNodeType = treeNodeType; } public Integer getPosition() { return position; } public void setPosition(Integer position) { this.position = position; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public TreeNode getParent() { return parent; } public void setParent(TreeNode parent) { this.parent = parent; } public Set<TreeNode> getChildren() { return children; } public void setChildren(Set<TreeNode> children) { this.children = children; } public Integer getInitChildren() { return initChildren; } public void setInitChildren(Integer initChildren) { this.initChildren = initChildren; } @Override public String toString() { return "TreeNode [nodeId=" + nodeId + ", nodeName=" + nodeName + ", treeNodeType=" + treeNodeType + ", position=" + position + ", url=" + url + "]"; } }
對應實體類的配置文件
TreeNode.hbm.xml
<?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 name="com.ht.four.entity.TreeNode" table="t_hibernate_sys_tree_node"> <id name="nodeId" type="java.lang.Integer" column="tree_node_id"> <generator class="increment" /> </id> <property name="nodeName" type="java.lang.String" column="tree_node_name"> </property> <property name="treeNodeType" type="java.lang.Integer" column="tree_node_type"> </property> <property name="position" type="java.lang.Integer" column="position"> </property> <property name="url" type="java.lang.String" column="url"> </property> <many-to-one name="parent" class="com.ht.four.entity.TreeNode" column="parent_node_id"/> <set name="children" cascade="save-update" inverse="true"> <key column="parent_node_id"></key> <one-to-many class="com.ht.four.entity.TreeNode"/> </set> </class> </hibernate-mapping>
在核心配置文件hibernate.cfg.xml中添加實體映射文件
<!-- 一對多的自關聯 --> <mapping resource="com/ht/four/entity/TreeNode.hbm.xml" />
Dao層
去控制數據庫中數據
package com.ht.four.dao; import org.hibernate.Hibernate; import org.hibernate.Session; import org.hibernate.Transaction; import com.ht.four.entity.TreeNode; import com.ht.two.util.SessionFactoryUtils; public class TreeNodeDao { public TreeNode load(TreeNode treeNode) { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); TreeNode t = session.load(TreeNode.class, treeNode.getNodeId()); if(t != null && new Integer(1).equals(treeNode.getInitChildren())) { Hibernate.initialize(t.getChildren()); Hibernate.initialize(t.getParent()); } transaction.commit(); session.close(); return t; } }
Junit測試類(用於測試映射關系的測試類)
TreeNodeDaoTest類
package com.ht.four.dao; import org.junit.Test; import com.ht.four.entity.TreeNode; public class TreeNodeDaoTest { private TreeNodeDao treeNodeDao = new TreeNodeDao(); @Test public void testLoad() { TreeNode treeNode = new TreeNode(); treeNode.setNodeId(6); treeNode.setInitChildren(1); TreeNode t = this.treeNodeDao.load(treeNode); System.out.println(t); System.out.println(t.getParent()); System.out.println(t.getChildren()); } }
運行結果如下圖:
二:Hibernate多對多測試案例
多對多級聯查詢 書籍表、書籍類別表
-
設計數據庫表
t_hibernate_book表
t_hibernate_category表
實體類
Book類
package com.ht.four.entity; import java.io.Serializable; import java.util.HashSet; import java.util.Set; public class Book implements Serializable{ // book_id int primary key auto_increment, // book_name varchar(50) not null, // price float not null private Integer bookId; private String bookName; private Float price; private Set<Category> categories = new HashSet<Category>(); private Integer initCategories = 0; public Integer getInitCategories() { return initCategories; } public void setInitCategories(Integer initCategories) { this.initCategories = initCategories; } 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; } public Set<Category> getCategories() { return categories; } public void setCategories(Set<Category> categories) { this.categories = categories; } @Override public String toString() { return "Book [bookId=" + bookId + ", bookName=" + bookName + ", price=" + price + "]"; } public Book(Integer bookId, String bookName) { super(); this.bookId = bookId; this.bookName = bookName; } public Book() { super(); } }
Category類
package com.ht.four.entity; import java.io.Serializable; import java.util.HashSet; import java.util.Set; public class Category implements Serializable{ // category_id int primary key auto_increment, // category_name varchar(50) not null private Integer categoryId; private String categoryName; private Set<Book> books = new HashSet<Book>(); 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; } public Set<Book> getBooks() { return books; } public void setBooks(Set<Book> books) { this.books = books; } @Override public String toString() { return "Category [categoryId=" + categoryId + ", categoryName=" + categoryName + "]"; } }
對應實體映射文件
book.hnm.xml
package com.ht.four.entity; import java.io.Serializable; import java.util.HashSet; import java.util.Set; public class Book implements Serializable{ // book_id int primary key auto_increment, // book_name varchar(50) not null, // price float not null private Integer bookId; private String bookName; private Float price; private Set<Category> categories = new HashSet<Category>(); private Integer initCategories = 0; public Integer getInitCategories() { return initCategories; } public void setInitCategories(Integer initCategories) { this.initCategories = initCategories; } 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; } public Set<Category> getCategories() { return categories; } public void setCategories(Set<Category> categories) { this.categories = categories; } @Override public String toString() { return "Book [bookId=" + bookId + ", bookName=" + bookName + ", price=" + price + "]"; } public Book(Integer bookId, String bookName) { super(); this.bookId = bookId; this.bookName = bookName; } public Book() { super(); } }
book.hbm.xml
<?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 name="com.ht.four.entity.Book" table="t_hibernate_book"> <cache usage="read-only" region="com.ht.four.entity.Book"/> <id name="bookId" type="java.lang.Integer" column="book_id"> <generator class="increment" /> </id> <property name="bookName" type="java.lang.String" column="book_name"> </property> <property name="price" type="java.lang.Float" column="price"> </property> <!-- table:代表中間表 name:書籍類的屬性 inverse:代表中間表交於對方維護 key:當前類對應的表列段在中間表中的外鍵 many-to-many: column:對應的是上面key查出來的另一張表的主鍵 class:上述查出來的主鍵對應的實體類 流程:以查詢 book_id=8這本書為例 1.通過建模反射自動生成sql,可以拿到book_id=8這條記錄的基本信息 2.book_id=8 必讀=8去查詢中間表 t_hibernate_book_category 拿到了cid=8,9 3.cid=8,9 t_hibernate_category的category_id=8,9 4.拿到了當前book實例對應的category的集合 5.最終{book_id=8,book_name=聖墟,price=40} --> <set table="t_hibernate_book_category" name="categories" cascade="save-update" inverse="false"> <!-- one --> <key column="bid"></key> <!-- many --> <many-to-many column="cid" class="com.ht.four.entity.Category"></many-to-many> </set> </class> </hibernate-mapping>
category.hbm.xml
<?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 name="com.ht.four.entity.Category" table="t_hibernate_category"> <id name="categoryId" type="java.lang.Integer" column="category_id"> <generator class="increment" /> </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.ht.four.entity.Book"></many-to-many> </set> </class> </hibernate-mapping>
在核心文件hibernate.cfg.xml中配置實體映射文件
<!-- 多對多實體配置文件 --> <mapping resource="com/ht/four/entity/book.hbm.xml" /> <mapping resource="com/ht/four/entity/category.hbm.xml" />
dao層
控制數據庫中的數據
package com.ht.four.dao; import java.util.HashMap; import java.util.List; import java.util.Map; import org.hibernate.Hibernate; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.query.Query; import com.ht.four.entity.Book; import com.ht.four.entity.Category; import com.ht.two.util.SessionFactoryUtils; public class BookDao{ public Integer addBook(Book book) { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); Integer bid = (Integer) session.save(book); transaction.commit(); session.close(); return bid; } public Integer addCategory(Category category) { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); Integer cid = (Integer) session.save(category); transaction.commit(); session.close(); return cid; } public Category getCategory(Category category) { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); Category c = session.get(Category.class, category.getCategoryId()); transaction.commit(); session.close(); return c; } public Book getBook(Book book) { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); Book b = session.get(Book.class, book.getBookId()); if (b != null && new Integer(1).equals(book.getInitCategories())) { Hibernate.initialize(b.getCategories()); } transaction.commit(); session.close(); return b; } public void delBook(Book book) { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); session.delete(book); transaction.commit(); session.close(); } public void delCategory(Category category) { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); Category c = session.get(Category.class, category.getCategoryId()); if(c!=null) { for (Book b : c.getBooks()) { // 通過在被控方通過主控方來解除關聯關系,最后被控方再做刪除 b.getCategories().remove(c); } } session.delete(c); transaction.commit(); session.close(); } }
junit測試類(給dao層測試他所寫的方法是否正確)
BookDaotext類
package com.ht.four.dao; import org.junit.Test; import com.ht.four.entity.Book; import com.ht.four.entity.Category; public class BookDaoTest { private BookDao bookDao = new BookDao(); @Test public void testGetBook() { Book book = new Book(); book.setBookId(3); book.setInitCategories(1); Book b = this.bookDao.getBook(book ); System.out.println(b.getBookName()); System.out.println(b.getCategories()); } /** * book.hbm.xml inverse=fasle * category.hbm.xml inverse=true * 數據添加正常 * 書籍表、橋接表各新增一條數據 */ @Test public void test1() { Book book = new Book(); book.setBookName("本是青燈不歸客"); book.setPrice(10f); Category category = new Category(); category.setCategoryId(5); // 直接將category對象加入到新建的book中是錯誤的,因為此時的category是臨時態的,hibernate是不會管理的 // book.getCategories().add(category); Category c = this.bookDao.getCategory(category); // c.getBooks().add(book); book.getCategories().add(c); this.bookDao.addBook(book); } /** * book.hbm.xml inverse=true * category.hbm.xml inverse=true * 只增加書籍表數據 * 橋接表不加數據 * 原因:雙方都沒有去維護關系 */ @Test public void test2() { Book book = new Book(); book.setBookName("c"); book.setPrice(10f); Category category = new Category(); category.setCategoryId(5); Category c = this.bookDao.getCategory(category); book.getCategories().add(c); this.bookDao.addBook(book); // c.getBooks().add(book); } }
我們來一個一個測試
首先測試查詢方法可不可行
@Test public void testGetBook() { Book book = new Book(); book.setBookId(3); book.setInitCategories(1); Book b = this.bookDao.getBook(book ); System.out.println(b.getBookName()); System.out.println(b.getCategories()); }
運行結果如下:
我們再來看新增方法可不可行
/** * book.hbm.xml inverse=fasle * category.hbm.xml inverse=true * 數據添加正常 * 書籍表、橋接表各新增一條數據 */ @Test public void test1() { Book book = new Book(); book.setBookName("本是青燈不歸客"); book.setPrice(10f); Category category = new Category(); category.setCategoryId(5); // 直接將category對象加入到新建的book中是錯誤的,因為此時的category是臨時態的,hibernate是不會管理的 // book.getCategories().add(category); Category c = this.bookDao.getCategory(category); // c.getBooks().add(book); book.getCategories().add(c); this.bookDao.addBook(book); }
運行結果如下:
配置inverse屬性去增加
category.hbm.xml、book.hbm.xml中inverse屬性皆為默認值true
只增加書籍表數據
橋接表不加數據
原因:雙方都沒有去維護關系
cateagory.hbm.xml
<set table="t_hibernate_book_category" name="books" cascade="save-update" inverse="true">
book.hbm.xml
<set table="t_hibernate_book_category" name="categories" cascade="save-update" inverse="true">
<!-- one -->
<key column="bid"></key>
<!-- many -->
<many-to-many column="cid" class="com.ht.four.entity.Category"></many-to-many>
</set>
謝謝觀看!!!