博客信息

hibernate关联关系

发布时间:『 2019-02-26 05:58』  博客类别:SSH  阅读(866)

本篇博客主要介绍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......


关键字:     hibernate  

备案号:湘ICP备19000029号

Copyright © 2018-2019 javaxl晓码阁 版权所有