本篇博客主要介绍hibernate的关联关系(一对多,多对多)
1、一对多的配置文件配置介绍
2、一对多如何通过代码进行级联新增
3、一对多的懒加载问题及解决方案
4、一对多的级联删除
5、一对多的自关联
6、多对多的配置文件介绍
7、多对多的查询
8、多对多的新增(inverse属性详解)
9、多对多的级联删除(慎用,会将三张表的数据清空)
1、一对多的配置文件配置介绍
<class name="com.javaxl.three.entity.Order" table="t_hibernate_order"> <id name="orderId" type="java.lang.Integer" column="order_id"> <generator class="increment" /> </id> <property name="orderNo" type="java.lang.String" column="order_no"> </property> <!-- Exception in thread "main" java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.util.Set --> <bag lazy="true" name="orderItems" cascade="save-update" inverse="true"> <key column="oid"></key> <one-to-many class="com.javaxl.three.entity.OrderItem" /> </bag> </class>
<class name="com.javaxl.three.entity.OrderItem" table="t_hibernate_order_item"> <id name="orderItemId" type="java.lang.Integer" column="order_item_id"> <generator class="increment" /> </id> <property name="productId" type="java.lang.Integer" column="product_id"> </property> <property name="quantity" type="java.lang.Integer" column="quantity"> </property> <property name="oid" type="java.lang.Integer" column="oid" insert="false" update="false"> </property> <many-to-one name="order" class="com.javaxl.three.entity.Order" column="oid"></many-to-one> </class>
注意:外键只能被hibernate所管理的对象中的一个属性所维护
2、一对多如何通过代码进行级联新增
/**
* 为了测试关系型映射文件配置准确
* 讲解insert=false,update=false的用途
* @param order
* @return
*/
public Integer addOrder(Order order) {
Session session = SessionFactoryUtils.openSession();
Transaction transaction = session.beginTransaction();
Integer oid = (Integer)session.save(order);
transaction.commit();
session.close();
return oid;
}
public Integer addOrderItem(OrderItem orderItem) {
Session session = SessionFactoryUtils.openSession();
Transaction transaction = session.beginTransaction();
Integer otid = (Integer)session.save(orderItem);
transaction.commit();
session.close();
return otid;
}/**
* 一方的新增
*/
@Test
public void testAddOrder() {
// Order order = new Order();
// order.setOrderNo("P3");
// System.out.println(orderDao.addOrder(order));
//配置关系的好处
Order order = new Order();
order.setOrderNo("P5");
OrderItem orderItem;
for(int i =0; i<6 ;i++) {
orderItem = new OrderItem();
orderItem.setOid(i);
orderItem.setProductId(i);
orderItem.setQuantity(i);
orderItem.setOrder(order );
order.getOrderItems().add(orderItem);
}
this.demoDao.addOrder(order);
}
/**
* 多方的新增
*/
@Test
public void testAddOrderItem() {
OrderItem orderItem;
for(int i =0; i<6 ;i++) {
orderItem = new OrderItem();
orderItem.setOid(i);
orderItem.setProductId(i);
orderItem.setQuantity(i);
Order order = new Order();
order.setOrderId(3);
orderItem.setOrder(order );
Integer otid = demoDao.addOrderItem(orderItem);
System.out.println(otid);
}
// Repeated column in mapping for entity: com.javaxl.four.entity.OrderItem column:
// oid (should be mapped with insert="false" update="false")
// 原因是同一个表中的字段被映射了两次
// System.out.println(otid);
}3、一对多的懒加载问题及解决方案
/**
* 为了讲解懒加载的问题(hibernate3.0后所有查询方式默认采用的是懒加载方式)
* 1、查单个时存在问题,代理对象已经关闭
* 2、查多个存在问题,有性能的问题
* @param order
* @return
*/
public Order getOrder(Order order) {
Session session = SessionFactoryUtils.openSession();
Transaction transaction = session.beginTransaction();
Order o = session.get(Order.class, order.getOrderId());
if(o != null && new Integer(1).equals(order.getInitChildren())) {
Hibernate.initialize(o.getOrderItems());
// System.out.println(o.getOrderItems());
}
transaction.commit();
session.close();
return o;
}
public List<Order> getOrderList() {
Session session = SessionFactoryUtils.openSession();
Transaction transaction = session.beginTransaction();
List<Order> list = session.createQuery("from Order").list();
transaction.commit();
session.close();
return list;
}/**
* 懒加载测试
*/
@Test
public void testGetOrder() {
Order order = new Order();
order.setOrderId(8);
order.setInitChildren(1);
Order o = this.demoDao.getOrder(order);
System.out.println(o.getOrderNo());
// failed to lazily initialize a collection of role: com.javaxl.four.entity.Order.orderItems,
// could not initialize proxy - no Session
// 由于查询默认采用的是懒加载的方式,加载主表对应的实体类,拿到了从表对应的实体类的oid,
// 并且保留在org.hibernate.collection.internal.PersistentSet这个代理对象中。
// 等要获取从表的对应实体类额确切信息是,这是session已经关闭了。
System.out.println(o.getOrderItems());
// org.hibernate.collection.internal.PersistentSet
// System.out.println(o.getOrderItems().getClass().getName());
}
/**
* 懒加载 lazy设置为false的弊端
*/
@Test
public void testGetOrderList() {
List<Order> orderList = demoDao.getOrderList();
for (Order order : orderList) {
System.out.println(order.getOrderNo());
// System.out.println(order.getOrderItems());
}
}
注意:hibernate3之后lazy默认为true,lazy=true会引发一个问题,不能加载关联属性,但是将lazy设置为false的话,又会造成查询多条主表数据的时候性能变差,这时我们采取的措施是
在主表对应的实体类中添加一个是否强制加载的控制字段;
4、一对多的级联删除
/**
* z主表的数据不能随便删除,得先删除从表中对应信息,才能删除主表的信息。
* @param order
*/
public void delOrder(Order order) {
Session session = SessionFactoryUtils.openSession();
Transaction transaction = session.beginTransaction();
Order order2 = session.get(Order.class, order.getOrderId());
for (OrderItem oi : order2.getOrderItems()) {
session.delete(oi);
}
session.delete(order2);
// session.delete(order);
transaction.commit();
session.close();
}/**
* 级联删除
*/
@Test
public void testDelOrder() {
Order order = new Order();
order.setOrderId(3);
this.demoDao.delOrder(order );
}5、一对多的自关联
<class name="com.javaxl.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.javaxl.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.javaxl.four.entity.TreeNode"/> </set> </class>
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;
}@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());
}6、多对多的配置文件介绍
<class name="com.javaxl.four.entity.Book" table="t_hibernate_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> <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.javaxl.four.entity.Category"></many-to-many> </set> </class>
<class name="com.javaxl.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.javaxl.four.entity.Book"></many-to-many> </set> </class>
注意:key对应的column不要填反,这里填的是当前类所映射的表的主键,所对应的桥接表中的外键
7、多对多的查询
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;
}@Test
public void testGetBook() {
Book book = new Book();
book.setBookId(1);
book.setInitCategories(1);
Book b = this.bookDao.getBook(book );
System.out.println(b.getBookName());
System.out.println(b.getCategories());
}8、多对多的新增(inverse属性详解)
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;
}/**
* book.hbm.xml inverse=fasle
* category.hbm.xml inverse=true
* 数据添加正常
* 书籍表、桥接表各新增一条数据
*/
@Test
public void test1() {
Book book = new Book();
book.setBookName("b");
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);
}
/**
* inverse进一步讲解
*/
@Test
public void test3() {
Category category = new Category();
category.setCategoryName("7");
Book book = new Book();
book.setBookId(6);
Book b = bookDao.getBook(book);
category.getBooks().add(b);
this.bookDao.addCategory(category);
}9、多对多的级联删除(慎用,会将三张表的数据清空)
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();
}/**
* 书籍为主控方
*/
@Test
public void test4() {
Book book = new Book();
book.setBookId(3);
this.bookDao.delBook(book);
}
@Test
public void test5() {
Category category = new Category();
category.setCategoryId(1);
this.bookDao.delCategory(category);
}over......
备案号:湘ICP备19000029号
Copyright © 2018-2019 javaxl晓码阁 版权所有