1. hibernate的多对多
hibernate可以直接映射多对多关联关系(看作两个一对多)2 多对多关系注意事项
2.1 一定要定义一个主控方2.2 多对多删除
2.2.1 主控方直接删除
2.2.2 被控方先通过主控方解除多对多关系,再删除被控方
2.2.3 禁用级联删除
2.3 关联关系编辑,不需要直接操作桥接表,hibernate的主控方会自动维护
3 hibernate自关联案列
3.1 表信息
t_hibernate_sys_tree_node
3.2 实体类 TreeNode
1 package com.yuan.four.entity; 2 3 import java.util.HashSet; 4 import java.util.Set; 5 6 public class TreeNode { 7 private Integer nodeId; 8 private String nodeName; 9 private Integer treeNodeType; 10 private Integer position; 11 private String url; 12 private TreeNode parent; 13 private Set<TreeNode> children = new HashSet<TreeNode>(); 14 private Integer initChildren = 0; 15 16 public Integer getNodeId() { 17 return nodeId; 18 } 19 20 public void setNodeId(Integer nodeId) { 21 this.nodeId = nodeId; 22 } 23 24 public String getNodeName() { 25 return nodeName; 26 } 27 28 public void setNodeName(String nodeName) { 29 this.nodeName = nodeName; 30 } 31 32 public Integer getTreeNodeType() { 33 return treeNodeType; 34 } 35 36 public void setTreeNodeType(Integer treeNodeType) { 37 this.treeNodeType = treeNodeType; 38 } 39 40 public Integer getPosition() { 41 return position; 42 } 43 44 public void setPosition(Integer position) { 45 this.position = position; 46 } 47 48 public String getUrl() { 49 return url; 50 } 51 52 public void setUrl(String url) { 53 this.url = url; 54 } 55 56 public TreeNode getParent() { 57 return parent; 58 } 59 60 public void setParent(TreeNode parent) { 61 this.parent = parent; 62 } 63 64 public Set<TreeNode> getChildren() { 65 return children; 66 } 67 68 public void setChildren(Set<TreeNode> children) { 69 this.children = children; 70 } 71 72 public Integer getInitChildren() { 73 return initChildren; 74 } 75 76 public void setInitChildren(Integer initChildren) { 77 this.initChildren = initChildren; 78 } 79 80 @Override 81 public String toString() { 82 return "TreeNode [nodeId=" + nodeId + ", nodeName=" + nodeName + ", treeNodeType=" + treeNodeType 83 + ", position=" + position + ", url=" + url + ", parent=" + parent + ", initChildren=" + initChildren 84 + "]"; 85 } 86 87 88 89 90 91 92 }
3.3 实体映射文件 TreeNode.hbm.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC 3 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 5 <hibernate-mapping> 6 <class name="com.yuan.four.entity.TreeNode" table="t_hibernate_sys_tree_node"> 7 <id name="nodeId" type="java.lang.Integer" column="tree_node_id"> 8 <generator class="increment" /> 9 </id> 10 <property name="nodeName" type="java.lang.String" 11 column="tree_node_name"> 12 </property> 13 <property name="treeNodeType" type="java.lang.Integer" 14 column="tree_node_type"> 15 </property> 16 <property name="position" type="java.lang.Integer" 17 column="position"> 18 </property> 19 <property name="url" type="java.lang.String" 20 column="url"> 21 </property> 22 23 <many-to-one name="parent" class="com.yuan.four.entity.TreeNode" column="parent_node_id"/> 24 25 <set name="children" cascade="save-update" inverse="true"> 26 <key column="parent_node_id"></key> 27 <one-to-many class="com.yuan.four.entity.TreeNode"/> 28 </set> 29 </class> 30 </hibernate-mapping>
3.4 将实体映射文件配置到 hibernate.cfg.xml 核心配置文件中
一对多自关联关系
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-configuration PUBLIC 3 "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 4 "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> 5 <hibernate-configuration> 6 <session-factory> 7 <!-- 1. 数据库相关 --> 8 <property name="connection.username">root</property> 9 <property name="connection.password" >123</property> 10 <property name="connection.url">jdbc:mysql://localhost:3306/xm_sc?useUnicode=true&characterEncoding=UTF-8 11 </property> 12 <property name="connection.driver_class">com.mysql.jdbc.Driver</property> 13 <property name="dialect">org.hibernate.dialect.MySQLDialect</property> 14 15 <!-- 配置本地事务(No CurrentSessionContext configured!) --> 16 <property name="hibernate.current_session_context_class">thread</property> 17 18 <!-- 2. 调试相关 --> 19 <property name="show_sql">true</property> 20 <property name="format_sql">true</property> 21 22 <!-- 3. 添加实体映射文件 --> 23 <mapping resource="com/yuan/one/entity/User.hbm.xml" /> 24 <!-- 主键生成策略 --> 25 <mapping resource="com/yuan/two/Student.hbm.xml" /> 26 <mapping resource="com/yuan/two/Worker.hbm.xml"/> 27 <!-- 一对多关联关系 --> 28 <mapping resource="com/yuan/three/entity/Order.hbm.xml" /> 29 <mapping resource="com/yuan/three/entity/OrderItem.hbm.xml"/> 30 <!-- 一对多自关联关系 --> 31 <mapping resource="com/yuan/four/entity/TreeNode.hbm.xml"/> 32
35 </session-factory> 36 </hibernate-configuration>
3.5 dao层 TreeNodeDao
1 package com.yuan.four.dao; 2 3 import org.hibernate.Hibernate; 4 import org.hibernate.Session; 5 import org.hibernate.Transaction; 6 7 import com.yuan.four.entity.TreeNode; 8 import com.yuan.two.util.SessionFactoryUtils; 9 10 11 public class TreeNodeDao { 12 public TreeNode load(TreeNode treeNode) { 13 Session session = SessionFactoryUtils.openSession(); 14 Transaction transaction = session.beginTransaction(); 15 TreeNode t = session.load(TreeNode.class, treeNode.getNodeId()); 16 if(t != null && new Integer(1).equals(treeNode.getInitChildren())) { 17 Hibernate.initialize(t.getChildren()); 18 Hibernate.initialize(t.getParent()); 19 } 20 transaction.commit(); 21 session.close(); 22 return t; 23 } 24 }
3.6 使用junit测试dao方法 TreeNodeDaoTest
1 package com.yuan.four.dao; 2 3 import org.junit.Test; 4 5 import com.yuan.four.entity.TreeNode; 6 7 public class TreeNodeDaoTest { 8 9 private TreeNodeDao treeNodeDao = new TreeNodeDao(); 10 11 // @Before 12 // public void setUp() throws Exception { 13 // } 14 // 15 // @After 16 // public void tearDown() throws Exception { 17 // } 18 19 @Test 20 public void testLoad() { 21 TreeNode treeNode = new TreeNode(); 22 treeNode.setNodeId(6); 23 treeNode.setInitChildren(1); 24 25 TreeNode t = this.treeNodeDao.load(treeNode); 26 System.out.println(t); 27 System.out.println(t.getParent()); 28 System.out.println(t.getChildren()); 29 } 30 31 32 }
3.7 测试得到结果
TreeNode [nodeId=6, nodeName=权限管理, treeNodeType=1, position=6, url=null, parent=TreeNode [nodeId=1, nodeName=系统管理, treeNodeType=1, position=1, url=null, parent=null, initChildren=0], initChildren=0] TreeNode [nodeId=1, nodeName=系统管理, treeNodeType=1, position=1, url=null, parent=null, initChildren=0] [TreeNode [nodeId=10, nodeName=用户分配角色, treeNodeType=2, position=10, url=null, parent=TreeNode [nodeId=6, nodeName=权限管理, treeNodeType=1, position=6, url=null, parent=TreeNode [nodeId=1, nodeName=系统管理, treeNodeType=1, position=1, url=null, parent=null, initChildren=0], initChildren=0], initChildren=0], TreeNode [nodeId=11, nodeName=角色授予用户, treeNodeType=2, position=11, url=null, parent=TreeNode [nodeId=6, nodeName=权限管理, treeNodeType=1, position=6, url=null, parent=TreeNode [nodeId=1, nodeName=系统管理, treeNodeType=1, position=1, url=null, parent=null, initChildren=0], initChildren=0], initChildren=0]]
4. 多对多关联关系案列
4.1 表信息
t_hibernate_book
t_hibernate_book_category 中间表
t_hibernate_category
4.2 创建实体类
Book.java
1 package com.yuan.four.entity; 2 3 import java.io.Serializable; 4 import java.util.HashSet; 5 import java.util.Set; 6 7 /** 8 * 一对多,一本书对应多种书本类型 9 * @author ly 10 * 11 */ 12 public class Book implements Serializable{ 13 // book_id int primary key auto_increment, 14 // book_name varchar(50) not null, 15 // price float not null 16 private Integer bookId; 17 private String bookName; 18 private Float price; 19 20 private Set<Category> categories = new HashSet<Category>(); 21 private Integer initCategories = 0; 22 23 public Integer getInitCategories() { 24 return initCategories; 25 } 26 27 public void setInitCategories(Integer initCategories) { 28 this.initCategories = initCategories; 29 } 30 31 public Integer getBookId() { 32 return bookId; 33 } 34 35 public void setBookId(Integer bookId) { 36 this.bookId = bookId; 37 } 38 39 public String getBookName() { 40 return bookName; 41 } 42 43 public void setBookName(String bookName) { 44 this.bookName = bookName; 45 } 46 47 public Float getPrice() { 48 return price; 49 } 50 51 public void setPrice(Float price) { 52 this.price = price; 53 } 54 55 public Set<Category> getCategories() { 56 return categories; 57 } 58 59 public void setCategories(Set<Category> categories) { 60 this.categories = categories; 61 } 62 63 @Override 64 public String toString() { 65 return "Book [bookId=" + bookId + ", bookName=" + bookName + ", price=" + price + "]"; 66 } 67 68 public Book(Integer bookId, String bookName) { 69 super(); 70 this.bookId = bookId; 71 this.bookName = bookName; 72 } 73 74 public Book() { 75 super(); 76 } 77 78 79 }
category.java
1 package com.yuan.four.entity; 2 3 import java.io.Serializable; 4 import java.util.HashSet; 5 import java.util.Set; 6 7 /** 8 * 一对多,一种书本类型对应多本书 9 * @author ly
10 * 11 */ 12 public class Category implements Serializable{ 13 // category_id int primary key auto_increment, 14 // category_name varchar(50) not null 15 private Integer categoryId; 16 private String categoryName; 17 private Set<Book> books = new HashSet<Book>(); 18 public Integer getCategoryId() { 19 return categoryId; 20 } 21 public void setCategoryId(Integer categoryId) { 22 this.categoryId = categoryId; 23 } 24 public String getCategoryName() { 25 return categoryName; 26 } 27 public void setCategoryName(String categoryName) { 28 this.categoryName = categoryName; 29 } 30 public Set<Book> getBooks() { 31 return books; 32 } 33 public void setBooks(Set<Book> books) { 34 this.books = books; 35 } 36 @Override 37 public String toString() { 38 return "Category [categoryId=" + categoryId + ", categoryName=" + categoryName + "]"; 39 } 40 41 }
4.3 实体类对应的实体映射文件
book.hbm.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC 3 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 5 <hibernate-mapping> 6 <class name="com.yuan.four.entity.Book" table="t_hibernate_book"> 7 <cache usage="read-only" region="com.zking.five.entity.Book"/> 8 <id name="bookId" type="java.lang.Integer" column="book_id"> 9 <generator class="increment" /> 10 </id> 11 <property name="bookName" type="java.lang.String" 12 column="book_name"> 13 </property> 14 <property name="price" type="java.lang.Float" 15 column="price"> 16 </property> 17 18 <!-- 19 set标签: 20 table:对应的是中间表,没有实体类的,意味着两张主表对应的映射文件联合管理数据 21 name:当前映射文件对应的实体类对应的属性 22 cascade:级联新增修改,说白了就是当前实体类对应的表删除能否影响到关联表的数据 23 inverse:中间表的数据维护的权力交给对方 24 key标签: 25 column:当前表t_hibernate_book的主键book_id在中间表的列段bid 26 many-to-many: 27 column:代表中间表对应的除去当前表t_hibernate_book的非主键的中间表列段cid 28 class:cid对应的类 29 30 31 --> 32 <set table="t_hibernate_book_category" name="categories" cascade="save-update" inverse="false"> 33 <!-- one --> 34 <key column="bid"></key> 35 <!-- many --> 36 <many-to-many column="cid" class="com.yuan.four.entity.Category"></many-to-many> 37 </set> 38 </class> 39 </hibernate-mapping>
category.hbm.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC 3 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 5 <hibernate-mapping> 6 <class name="com.yuan.four.entity.Category" table="t_hibernate_category"> 7 <id name="categoryId" type="java.lang.Integer" column="category_id"> 8 <generator class="increment" /> 9 </id> 10 <property name="categoryName" type="java.lang.String" 11 column="category_name"> 12 </property> 13 14 <set table="t_hibernate_book_category" name="books" cascade="save-update" inverse="true"> 15 <key column="cid"></key> 16 <many-to-many column="bid" class="com.yuan.four.entity.Book"></many-to-many> 17 </set> 18 </class> 19 </hibernate-mapping>
4.4 将实体映射文件配置到hibernate.cfg.xml 中
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-configuration PUBLIC 3 "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 4 "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> 5 <hibernate-configuration> 6 <session-factory> 7 <!-- 1. 数据库相关 --> 8 <property name="connection.username">root</property> 9 <property name="connection.password" >123</property> 10 <property name="connection.url">jdbc:mysql://localhost:3306/xm_sc?useUnicode=true&characterEncoding=UTF-8 11 </property> 12 <property name="connection.driver_class">com.mysql.jdbc.Driver</property> 13 <property name="dialect">org.hibernate.dialect.MySQLDialect</property> 14 15 <!-- 配置本地事务(No CurrentSessionContext configured!) --> 16 <property name="hibernate.current_session_context_class">thread</property> 17 18 <!-- 2. 调试相关 --> 19 <property name="show_sql">true</property> 20 <property name="format_sql">true</property> 21 22 <!-- 3. 添加实体映射文件 --> 23 <mapping resource="com/yuan/one/entity/User.hbm.xml" /> 24 <!-- 主键生成策略 --> 25 <mapping resource="com/yuan/two/Student.hbm.xml" /> 26 <mapping resource="com/yuan/two/Worker.hbm.xml"/> 27 <!-- 一对多关联关系 --> 28 <mapping resource="com/yuan/three/entity/Order.hbm.xml" /> 29 <mapping resource="com/yuan/three/entity/OrderItem.hbm.xml"/> 30 <!-- 一对多自关联关系 --> 31 <mapping resource="com/yuan/four/entity/TreeNode.hbm.xml"/> 32 <!-- 多对多关联关系 --> 33 <mapping resource="com/yuan/four/entity/book.hbm.xml"/> 34 <mapping resource="com/yuan/four/entity/category.hbm.xml"/> 35 </session-factory> 36 </hibernate-configuration>
4.5 编写dao层
BookDao
1 package com.yuan.four.dao; 2 3 4 import org.hibernate.Hibernate; 5 import org.hibernate.Session; 6 import org.hibernate.Transaction; 7 8 import com.yuan.four.entity.Book; 9 import com.yuan.four.entity.Category; 10 import com.yuan.two.util.SessionFactoryUtils; 11 12 13 public class BookDao { 14 public Integer addBook(Book book) { 15 Session session = SessionFactoryUtils.openSession(); 16 Transaction transaction = session.beginTransaction(); 17 Integer bid = (Integer) session.save(book); 18 transaction.commit(); 19 session.close(); 20 return bid; 21 } 22 23 public Integer addCategory(Category category) { 24 Session session = SessionFactoryUtils.openSession(); 25 Transaction transaction = session.beginTransaction(); 26 Integer cid = (Integer) session.save(category); 27 transaction.commit(); 28 session.close(); 29 return cid; 30 } 31 32 public Category getCategory(Category category) { 33 Session session = SessionFactoryUtils.openSession(); 34 Transaction transaction = session.beginTransaction(); 35 Category c = session.get(Category.class, category.getCategoryId()); 36 transaction.commit(); 37 session.close(); 38 return c; 39 } 40 41 public Book getBook(Book book) { 42 Session session = SessionFactoryUtils.openSession(); 43 Transaction transaction = session.beginTransaction(); 44 Book b = session.get(Book.class, book.getBookId()); 45 if (b != null && new Integer(1).equals(book.getInitCategories())) { 46 Hibernate.initialize(b.getCategories()); 47 } 48 transaction.commit(); 49 session.close(); 50 return b; 51 } 52 53 public void delBook(Book book) { 54 Session session = SessionFactoryUtils.openSession(); 55 Transaction transaction = session.beginTransaction(); 56 session.delete(book); 57 transaction.commit(); 58 session.close(); 59 } 60 61 public void delCategory(Category category) { 62 Session session = SessionFactoryUtils.openSession(); 63 Transaction transaction = session.beginTransaction(); 64 Category c = session.get(Category.class, category.getCategoryId()); 65 if(c!=null) { 66 for (Book b : c.getBooks()) { 67 // 通过在被控方通过主控方来解除关联关系,最后被控方再做删除 68 b.getCategories().remove(c); 69 } 70 } 71 session.delete(c); 72 transaction.commit(); 73 session.close(); 74 } 75 76 77 78 }
4.6 BookDao 的junit测试 BookDaoTest
1 package com.yuan.four.dao; 2 3 import org.junit.Test; 4 5 import com.yuan.four.entity.Book; 6 import com.yuan.four.entity.Category; 7 8 9 public class BookDaoTest { 10 private BookDao bookDao = new BookDao(); 11 //获取单本书籍部分信息 12 @Test 13 public void testGetBook() { 14 Book book = new Book(); 15 book.setBookId(8); 16 book.setInitCategories(1); 17 Book b = this.bookDao.getBook(book ); 18 System.out.println(b.getBookName()); 19 System.out.println(b.getCategories()); 20 } 21 22 /** 23 * book.hbm.xml inverse=false 24 * category.hbm.xml inverse=true 25 * 数据添加正常 26 * 书籍表、桥接表各新增一条数据 27 */ 28 @Test 29 public void test1() { 30 Book book = new Book(); 31 book.setBookName("yuan"); 32 book.setPrice(10f); 33 Category category = new Category(); 34 category.setCategoryId(5); 35 // 直接将category对象加入到新建的book中是错误的,因为此时的category是临时态的,hibernate是不会管理的 36 // book.getCategories().add(category); 37 Category c = this.bookDao.getCategory(category); 38 39 // c.getBooks().add(book); 40 book.getCategories().add(c); 41 this.bookDao.addBook(book); 42 } 43 44 /** 45 * book.hbm.xml inverse=true 46 * category.hbm.xml inverse=true 47 * 只增加书籍表数据 48 * 桥接表不加数据 49 * 原因:双方都没有去维护关系 50 */ 51 @Test 52 public void test2() { 53 Book book = new Book(); 54 book.setBookName("yuan2"); 55 book.setPrice(10f); 56 Category category = new Category(); 57 category.setCategoryId(5); 58 Category c = this.bookDao.getCategory(category); 59 60 book.getCategories().add(c); 61 this.bookDao.addBook(book); 62 // c.getBooks().add(book); 63 } 64 65 66 }
4.7 测试结果
注:测试时请根据测试方法上的注解进行修改
4.7.1 testGetBook() 方法测试
4.7.2 test1()测试
t_hibernate_book表新增一条数据
同时 t_hibernate_book_category 表新增一条数据
4.7.3 test2()测试
t_hibernate_book新增数据
但t_hibernate_book_category不新增数据
完 !!!