Objectives:
1: Understanding one to many relationships
2: Understand lazy loading and forced loading
3: Understanding one to many autocorrelation
4: Understanding many to many relationships
1, One to many association, lazy loading and forced loading
One to many association configuration (environment: order (1) and order details (many)), lazy loading and forced loading
Entity class, dao layer, xml file and test class to be used
Entity class Order:
package com.dzl.two.entity; import java.util.HashSet; import java.util.Set; public class Order { // create table t_hibernate_order // ( // order_id int primary key auto_increment, // order_no varchar(50) not null // ); private Integer orderId; private String orderNo; //Note: variable attributes must be accepted by the interface private Set<OrderItem> orderItems = new HashSet<>(); private Integer initOrderItems = 0;//0 represents lazy loading and 1 represents forced loading public Integer getInitOrderItems() { return initOrderItems; } public void setInitOrderItems(Integer initOrderItems) { this.initOrderItems = initOrderItems; } public Set<OrderItem> getOrderItems() { return orderItems; } public void setOrderItems(Set<OrderItem> orderItems) { this.orderItems = orderItems; } public Integer getOrderId() { return orderId; } public void setOrderId(Integer orderId) { this.orderId = orderId; } public String getOrderNo() { return orderNo; } public void setOrderNo(String orderNo) { this.orderNo = orderNo; } }
Entity class OrderItem:
package com.dzl.two.entity; public class OrderItem { // create table t_hibernate_order_item // ( // order_item_id int primary key auto_increment, // product_id int not null, // quantity int not null, // oid int not null, // foreign key(oid) references t_hibernate_order(order_id) // ); private Integer orderItemId; private Integer productId; private Integer quantity; private Integer oid; private Order order; public Order getOrder() { return order; } public void setOrder(Order order) { this.order = order; } public Integer getOrderItemId() { return orderItemId; } public void setOrderItemId(Integer orderItemId) { this.orderItemId = orderItemId; } public Integer getProductId() { return productId; } public void setProductId(Integer productId) { this.productId = productId; } public Integer getQuantity() { return quantity; } public void setQuantity(Integer quantity) { this.quantity = quantity; } public Integer getOid() { return oid; } public void setOid(Integer oid) { this.oid = oid; } }
XML file Order.hbm.xml OrderItem.hbm.xml
Order.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.dzl.two.entity.Order" table="t_hibernate_order"> <id name="orderId" type="java.lang.Integer" column="order_id"> <generator class="increment"></generator> </id> <property name="orderNo" type="java.lang.String" column="order_no"/> <!-- cascade:Cascade attribute configuration inverse: Is the relationship maintained by the other party? --> <set name="orderItems" cascade="save-update" inverse="true"> <key column="oid"></key> <one-to-many class="com.sg.two.entity.OrderItem"/> </set> </class> </hibernate-mapping>
OrderItem.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.dzl.two.entity.OrderItem" table="t_hibernate_order_item"> <id name="orderItemId" type="java.lang.Integer" column="order_item_id"> <generator class="increment"></generator> </id> <property name="productId" type="java.lang.Integer" column="product_id"/> <property name="quantity" type="java.lang.Integer" column="quantity"/> <property name="oid" type="java.lang.Integer" column="oid"/> <!-- Repeated column in mapping for entity: com.zking.four.entity.OrderItem column: oid (should be mapped with insert="false" update="false") --> <many-to-one name="order" class="com.sg.two.entity.Order" insert="false" update="false" column="oid"></many-to-one> </class> </hibernate-mapping>
Test class: OrderDaoTest and dao layer: OrderDao/OrderItemDao
OrderDaoTest:
package com.dzl.two.dao; import java.util.List; import org.junit.Test; import com.sg.two.entity.Order; public class OrderDaoTest { private OrderDao orderDao = new OrderDao(); /** * org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.zking.two.entity.Order.orderItems, could not initialize proxy - no Session * 1.Normal query * 2.Lazy load exception error * 3.performance tuning */ @Test public void testGet() { Order order = new Order(); order.setOrderId(7); // order.setInitOrderItems(1); Order o = this.orderDao.get(order); System.out.println(o.getOrderNo()); // System.out.println(o.getOrderItems()); } @Test public void testList() { List<Order> list = this.orderDao.list(); for (Order o : list) { System.out.println(o.getOrderNo()); // System.out.println(o.getOrderItems().size()); } } @Test public void testDelete() { Order order = new Order(); order.setOrderId(6); this.orderDao.delete(order); } }
OrderDao:
package com.dzl.two.dao; import java.util.Iterator; import java.util.List; import org.hibernate.Hibernate; import org.hibernate.Session; import org.hibernate.Transaction; import com.dzl.two.entity.Order; import com.dzl.two.entity.OrderItem; import com.dzl.two.util.SessionFactoryUtil; public class OrderDao { public Order get(Order order) { Session session = SessionFactoryUtil.getSession(); Transaction transaction = session.beginTransaction(); Order o = session.get(Order.class, order.getOrderId()); // In addition, if you want to query the data of associated order items, you can use forced loading if(o != null && new Integer(1).equals(order.getInitOrderItems())) { Hibernate.initialize(o.getOrderItems()); } transaction.commit(); session.close(); return o; } public List<Order> list() { Session session = SessionFactoryUtil.getSession(); Transaction transaction = session.beginTransaction(); List<Order> list = session.createQuery("from Order").list(); for (Order o: list) { Hibernate.initialize(o.getOrderItems()); } transaction.commit(); session.close(); return list; } public void delete(Order order) { Session session = SessionFactoryUtil.getSession(); Transaction transaction = session.beginTransaction(); Order o = session.get(Order.class, order.getOrderId()); for(OrderItem oi:o.getOrderItems()) { session.delete(oi); } session.delete(o); transaction.commit(); session.close(); } }
OrderItemDao:
package com.dzl.two.dao; import org.hibernate.Session; import org.hibernate.Transaction; import com.dzl.two.entity.OrderItem; import com.dzl.two.util.SessionFactoryUtil; public class OrderItemDao { public OrderItem get(OrderItem orderItem) { Session session = SessionFactoryUtil.getSession(); Transaction transaction = session.beginTransaction(); OrderItem oi = session.get(OrderItem.class, orderItem.getOrderItemId()); transaction.commit(); session.close(); return oi; } }
When our database data is very large, it will occupy a lot of resources, and sometimes we only need to use it
Sometimes the data of the order table and the order details table are needed, so lazy loading will save a lot of time
Code resources, which is a tuning of performance.
2, One to many autocorrelation
Entity class, dao layer, xml file and test class to be used
(simulation environment: tree menu):
One to many self association means that you can have multiple child nodes, but the parent node has only one and is in your own table
Entity class TreeNode:
package com.dzl.two.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; 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 + ", children=" + children + "]"; // } @Override public String toString() { return "TreeNode [nodeId=" + nodeId + ", nodeName=" + nodeName + ", treeNodeType=" + treeNodeType + ", position=" + position + ", url=" + url + "]"; } }
The first is the parent node (there is only one parent node)
The second is a child node (there may be multiple child nodes, so it is wrapped in a collection)
The third is lazy loading (0 is lazy loading and 1 is forced loading)
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.sg.two.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.sg.two.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.sg.two.entity.TreeNode"/> </set> </class> </hibernate-mapping>
< many to one > many to one: multiple child nodes correspond to a parent node
One to many tags are placed in the < set > tag: a parent node corresponds to multiple child nodes
Test class TreeNodeDaoTest:
package com.dzl.two.dao; import org.junit.Test; import com.dzl.two.entity.TreeNode; public class TreeNodeDaoTest { private TreeNodeDao treeNodeDao = new TreeNodeDao(); // @Before // public void setUp() throws Exception { // } // // @After // public void tearDown() throws Exception { // } @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()); } }
dao layer TreeNodeDao:
package com.dzl.two.dao; import org.hibernate.Hibernate; import org.hibernate.Session; import org.hibernate.Transaction; import com.dzl.two.entity.TreeNode; import com.dzl.two.util.SessionFactoryUtil; public class TreeNodeDao { public TreeNode load(TreeNode treeNode) { Session session = SessionFactoryUtil.getSession(); 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; } }
3, Many to many Association
Entity class, dao layer, xml file and test class to be used
Analysis (simulation environment: teachers and their classes):
Many to many can be understood as two one to many:
Just like the above figure, a class can be managed by multiple teachers, and teachers can manage multiple classes
Entity class Book:
package com.dzl.two.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(); } }
Entity Category:
package com.dzl.two.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 + "]"; } }
In addition to the table structure, the two entity class tables also have set sets to enclose each other, indicating that they can be one to many
XML files: category.hbm.xml, book.hbm.xml
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.dzl.two.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.sg.two.entity.Book"></many-to-many> </set> </class> </hibernate-mapping>
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.sg.two.entity.Book" table="t_hibernate_book"> <!-- <cache usage="read-only" region="com.zking.five.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:Intermediate table name:Association properties inverse:reversal key:The primary key of the current table is the foreign key of the intermediate table many-to-many:The primary key of the current table finds the foreign key of another table in the intermediate table --> <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.dzl.two.entity.Category"></many-to-many> </set> </class> </hibernate-mapping>
ABCD method book dao:
package com.dzl.two.dao; import org.hibernate.Hibernate; import org.hibernate.Session; import org.hibernate.Transaction; import com.dzl.two.entity.Book; import com.dzl.two.entity.Category; import com.dzl.two.util.SessionFactoryUtil; public class BookDao /*extends BaseDao*/{ public Integer addBook(Book book) { Session session = SessionFactoryUtil.getSession(); Transaction transaction = session.beginTransaction(); Integer bid = (Integer) session.save(book); transaction.commit(); session.close(); return bid; } public Integer addCategory(Category category) { Session session = SessionFactoryUtil.getSession(); Transaction transaction = session.beginTransaction(); Integer cid = (Integer) session.save(category); transaction.commit(); session.close(); return cid; } public Category getCategory(Category category) { Session session = SessionFactoryUtil.getSession(); 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 = SessionFactoryUtil.getSession(); 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 = SessionFactoryUtil.getSession(); Transaction transaction = session.beginTransaction(); session.delete(book); transaction.commit(); session.close(); } public void delCategory(Category category) { Session session = SessionFactoryUtil.getSession(); Transaction transaction = session.beginTransaction(); Category c = session.get(Category.class, category.getCategoryId()); if(c!=null) { for (Book b : c.getBooks()) { // The accused party cancels the association relationship through the main control party, and finally the accused party deletes it b.getCategories().remove(c); } } session.delete(c); transaction.commit(); session.close(); } /* * hql Explain (need to inherit BaseDao) */ /** * No code before BaseDao is used * @param book * @param pageBean * @return */ // public List<Book> list(Book book, PageBean pageBean) { // Session session = SessionFactoryUtil.getSession(); // Transaction transaction = session.beginTransaction(); // String hql = "from Book where 1 = 1"; // // if (StringUtils.isNotBlank(book.getBookName())) { // hql += " and bookName like :bookName"; // } // // Query query = session.createQuery(hql); // // if (StringUtils.isNotBlank(book.getBookName())) { // query.setParameter("bookName", book.getBookName()); // } // // if (pageBean != null && pageBean.isPagination()) { // query.setFirstResult(pageBean.getStartIndex()); // query.setMaxResults(pageBean.getRows()); // } // List<Book> list = query.list(); // transaction.commit(); // session.close(); // return list; // // } /** * Code after using BaseDao * @param book * @param pageBean * @return */ // public List<Book> list2(Book book, PageBean pageBean) { // Session session = SessionFactoryUtil.getSession(); // Transaction transaction = session.beginTransaction(); // String hql = "from Book where 1 = 1"; // Map<String, Object> map = new HashMap<String, Object>(); // // if (StringUtils.isNotBlank(book.getBookName())) { // hql += " and bookName like :bookName"; // map.put("bookName", book.getBookName()); // } // List list = super.executeQuery(session, hql, map, pageBean); // transaction.commit(); // session.close(); // return list; // } /** * Use native SQL * @param book * @param pageBean * @return */ // public List list3(Book book, PageBean pageBean) { String sql = "select b.*,o.* from t_hibernate_book b,t_hibernate_Order o"; // String sql = "select * from t_hibernate_book"; // Session session = SessionFactoryUtil.getSession(); // Transaction transaction = session.beginTransaction(); // List list = session.createSQLQuery(sql).list(); // transaction.commit(); // session.close(); // return list; // } }
Test class: BookDaoTest:
package com.dzl.two.dao; import org.junit.Test; import com.dzl.two.entity.Book; import com.dzl.two.entity.Category; public class BookDaoTest { private BookDao bookDao = new BookDao(); @Test public void testGetBook() { Book book = new Book(); book.setBookId(8); 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 * Data addition is normal * Add a new piece of data to the book table and bridge table respectively */ @Test public void test1() { Book book = new Book(); book.setBookName("bbbb"); book.setPrice(10f); Category category = new Category(); category.setCategoryId(5); // It is wrong to directly add the category object to the new book, because the category is temporary and hibernate will not manage it // 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 * Only add book table data * Bridge table without data * Reason: neither side has maintained the relationship */ @Test public void test2() { Book book = new Book(); book.setBookName("dddd"); 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); } }