1, One to many association configuration
1. Association refers to the reference relationship between classes.
If class A is associated with class B, the referenced class B will be defined as an attribute of class A.
2. One to many association:
For example: order and order item. An order has multiple order items;
However, an order item has only one order;
3. Create entity classes and mapping files
① . entity class:
(1)Order
package com.ysq.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; } }
(2)OrderItem
package com.ysq.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; } }
② . mapping file:
(1)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.ysq.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.ysq.two.entity.OrderItem"/> </set> </class> </hibernate-mapping>
(2)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.ysq.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.ysq.two.entity.Order" insert="false" update="false" column="oid"></many-to-one> </class> </hibernate-mapping>
Core configuration file (hibernate.cfg.xml)
<!-- One to many -- >
<mapping resource="com/ysq/two/entity/Order.hbm.xml" />
<mapping resource="com/ysq/two/entity/OrderItem.hbm.xml" />
Tools:
package com.ysq.two.util; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; /** * 1,Used to produce session * 2,Used to test whether your hibernate configuration is correct * @author Administrator * */ public class SessionFactoryUtil { static SessionFactory sessionFactory; static { Configuration configure = new Configuration().configure("hibernate.cfg.xml"); sessionFactory = configure.buildSessionFactory(); } public static Session getSession() { Session session = sessionFactory.getCurrentSession(); if(session == null) { session = sessionFactory.openSession(); } return session; } public static void main(String[] args) { Session session = SessionFactoryUtil.getSession(); // Calling method 'isConnected' is not valid without an active transaction (Current status: NOT_ACTIVE) session.beginTransaction(); System.out.println(session.isConnected()); session.close(); System.out.println(session.isConnected()); } }
4. dao layer
①,OrderDao
package com.ysq.two.dao; import java.util.Iterator; import java.util.List; import org.hibernate.Hibernate; import org.hibernate.Session; import org.hibernate.Transaction; import com.ysq.two.entity.Order; import com.ysq.two.entity.OrderItem; import com.ysq.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())) { // Force loading order o associated order item data 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.ysq.two.dao; import org.hibernate.Session; import org.hibernate.Transaction; import com.ysq.two.entity.OrderItem; import com.ysq.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; } }
5,orderDaoTest
package com.ysq.two.dao; import java.util.List; import org.junit.Test; import com.ysq.two.entity.Order; public class OrderDaoTest { private OrderDao orderDao = new OrderDao(); /** * org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.ysq.two.entity.Order.orderItems, could not initialize proxy - no Session * 1.Normal query * 2.Lazy load exception error * 3.Performance tuning (explains why hibernate is lazy by default) * * Actual scenario: * 1.Use only data from the order table * Want lazy loading * 2.You need to use both order table and order item table data * Do not want lazy loading */ @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); } }
6. Testing
① . run testGet to get the corresponding order
@Test public void testGet() { Order order = new Order(); order.setOrderId(7); Order o = this.orderDao.get(order); System.out.println(o.getOrderNo()); }
Operation results:
The order of 7 was found
② . run testGet to get the order item corresponding to the order
@Test public void testGet() { Order order = new Order(); order.setOrderId(7); Order o = this.orderDao.get(order); System.out.println(o.getOrderNo()); System.out.println(o.getOrderItems()); }
Operation results:
Error reason: lazy loading is used by default. The session is closed when the above output is executed, so an error will be reported
resolvent:
Force load
@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()); }
Operation results:
Performance tuning (explains why hibernate uses lazy loading by default):
1. When only the data of the order table is needed, the data of the order item table will be queried at the same time, and the amount of sql statements used is huge;
2. It is controlled by fields, so lazy loading is 0 by default. When an order item is required, change the initOrderItems field of the order entity class to 1 to force loading.
2, One to many autocorrelation
Analysis (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
1. Entity class (TreeNode) mapping file (TreeNode.hbm.xml)
①,TreeNode
The only parent without a description_ node_ ID, because parent_node_id relates the association attribute between the current node and the parent node;
package com.ysq.two.entity; import java.util.HashSet; import java.util.Set; /** * Describe the relationship between order and orderitem into a class * @author zjjt * */ 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 + "]"; } }
② , mapping file
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.ysq.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.ysq.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.ysq.two.entity.TreeNode"/> </set> </class> </hibernate-mapping>
3. dao layer, configuration and testing
①,TreeNodeDao
package com.ysq.two.dao; import org.hibernate.Hibernate; import org.hibernate.Session; import org.hibernate.Transaction; import com.ysq.two.entity.TreeNode; import com.ysq.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; } }
② . core configuration file (hibernate.cfg.xml)
<!-- One to many autocorrelation -- >
<mapping resource="com/ysq/two/entity/TreeNode.hbm.xml" />
③,TreeNodeDaoTest
package com.ysq.two.dao; import org.junit.Test; import com.ysq.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()); } }
Operation results:
3, Many to many Association
Understanding: think of it as two one to many. There are two foreign keys in the middle table. Both tables and the middle table are one to many;
For example: Book and book category table, one book has multiple categories, and one category has multiple books;
1. Entity class and mapping file
① , books
(1),Book .
package com.ysq.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(); } }
(2) , mapping file
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.ysq.two.entity.Book" table="t_hibernate_book"> <!-- <cache usage="read-only" region="com.ysq.two.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="true"> <!-- one --> <key column="bid"></key> <!-- many --> <many-to-many column="cid" class="com.ysq.two.entity.Category"></many-to-many> </set> </class> </hibernate-mapping>
② . book category
(1),Category
package com.ysq.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 + "]"; } }
(2) , mapping file
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.ysq.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.ysq.two.entity.Book"></many-to-many> </set> </class> </hibernate-mapping>
Core configuration file (hibernate.cfg.xml)
<!-- Many to many -- >
<mapping resource="com/ysq/two/entity/Category.hbm.xml" />
<mapping resource="com/ysq/two/entity/Book.hbm.xml" />
2. dao method
BookDao
package com.ysq.two.dao; import org.hibernate.Hibernate; import org.hibernate.Session; import org.hibernate.Transaction; import com.ysq.two.entity.Book; import com.ysq.two.entity.Category; import com.ysq.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(); } }
TreeNodeDaoTest
package com.ysq.two.dao; import org.junit.Test; import com.ysq.two.entity.Book; import com.ysq.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("Sun Si's turtle"); book.setPrice(10f); Category category = new Category(); category.setCategoryId(13); // 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("Xiaobai autobiography"); 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); } }
3. Testing
① . get the books and book categories with ID 8
@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()); }
Operation results:
② One positive and one negative
/** * book.hbm.xml inverse=true * category.hbm.xml inverse=false * 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("Sun Si's turtle"); book.setPrice(10f); Category category = new Category(); category.setCategoryId(13); // 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); }
Operation results:
book table:
category table:
③ Both sides are true
** * 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("Xiaobai autobiography"); 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); }
Operation results:
book table:
category table: