天天看点

Hibernate关联关系一、单向N-1二、单向的1-1三、单向的1-N四、单向N-N懒加载删除对应数据hibernate框架一对多的执行原理

Hibernate关联就是将关联映射到数据库,所谓关联关系就是对象模型在内存中的一个或多个引用。

先看两个关系实体类: 都提供set/get方法

public class Order {
	private Integer orderId;
	private String orderNo;
	private List<OrderItem> orderItems = new ArrayList<>();
	private Integer initChildren =0;  //0代表懒加载  默认为0
	
}
           
public class OrderItem {
	private Integer orderItemId;
	private Integer productId;
	private Integer quantity;
	private Integer oid;
	private Order order;
}
           

下面介绍几种单向的关联关系。

文章目录

  • 一、单向N-1
  • 二、单向的1-1
  • 三、单向的1-N
  • 四、单向N-N
  • 懒加载
  • 删除对应数据
  • hibernate框架一对多的执行原理

一、单向N-1

所谓的单向1-N,也就是一个a实体类中有可以有多个b实体类的关系。

xml配置:

<many-to-one name="orderItem" column="productId"/>
           

二、单向的1-1

这种情况也是使用many-to-one,

不过在标签中多加一个unique=true这个属性,

这个属性代表的是限制了多的一端的多重性唯一。

通过这种手段可以映射一对一唯一外键关联。

xml配置:

<many-to-one name="address" column="oid" unique="true"/>
           

三、单向的1-N

一对多关联映射,在多的一端添加一个外键指向一的一端,它维护的关系是一指向多。

xml配置:

<!-- 
	bag标签:
		 lazy:是否懒加载,默认是懒加载
		 name:类的关联属性名
		 cascade:级联关系  级联新增与修改
		 inverse:关联关系交给对方控制,默认是true  意思就是当前类不维护关联关系
		 
		 子标签key:
		 	column:主表的主键,从表的外键。一般写从表的外键
		 子标签one-to-many:
		 	class:外键对应的实体类
		 
 -->
	<bag lazy="true" name="orderItems" cascade="save-update" inverse="true">
		<key column="oid"></key>
		<one-to-many class="com.zlk.three.entity.OrderItem"/>
	</bag>
           

在这里有两个选择,可以选择bag标签也可以使用set标签,

bag是一个无序的集合,它可以包含重复的元素,相当于java的java.util.List。

set类似于bag,但它只能存储唯一对象,若元素相同,则新的会替换掉旧的元素。类似Java中的java.util.Set。

四、单向N-N

两个实体类:

public class User {
	private int id;
	private String name;
	private Set roles;
}
           
public class Role {
private int id;
private String name;
}
           

现在需要映射这样的N-N关系,一个User可以有多个Role,而一个Role有可以被多个User所拥有。

这样我们就可以将一个N-N关系拆分为两个N-1的关系。

xml配置:

<bag name="roles" table="t_user_role">
<key column="userid"/>
<many-to-many class="xxx.Role" column="roleid"/>
</bag>
           

参考在这,想了解更多关系,请参考如何理解hibernate关联关系。

懒加载

四种模式已经介绍完了,在这里我先着重讲解一下1-N。

在1-N的xml配置中:

<bag lazy="true" name="orderItems" cascade="save-update" inverse="true">
			<key column="oid"></key>
			<one-to-many class="com.zlk.three.entity.OrderItem"/>
		</bag>
           

上面介绍过lazy是懒模式。他默认是true,那什么是懒模式呢?

当lazy= false 的时候,会让hibernate执行完两次操作,session才会关闭,

当lazy= true 的时候,会让hibernate执行完一次操作,session就会关闭

为什么要默认true呢?

出于性能的考虑,所以hibarnate3.0出现lazy这个属性,并让他默认等于true,也就是不加载关联属性。

可以使用JUnit测试一下,

@Test
	public void testGetOrder() {
		Order order = new Order();
		order.setOrderId(1);
		Order o = this.demoDao.getOrder(order );
		List<OrderItem> orderItems = o.getOrderItems();
		for (OrderItem orderItem : orderItems) {
			System.out.println(orderItem);
		}
		System.out.println(o);
	}
           

当lazy=false时候,他会正常运行,并打印出数据。

当lazy=true时候,他会报no-Session错,这是因为允许了懒加载,只执行了一次操作,所以 List orderItems = o.getOrderItems();这里面是没有值的,

但如果我只是单纯的写要查出所有的订单那怎么办呢?

这里就运用到了上面实体类中的private Integer initChildren =0; //0代表懒加载 默认为0。

通过这个属性来控制是否强制加载关联对象。

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());
		}
		transaction.commit();
		session.close();
		return o;
	}
           

这样就可以使用懒加载查看所有订单了。

删除对应数据

若你想删除订单的时候,这时候不能直接删除订单,因为你的从表OrderItem里面还是有数据的,所以你必须先删除从表里面的值,才可以删除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);
		transaction.commit();
		session.close();
	}
           

hibernate框架一对多的执行原理

hibernate框架一对多的执行原理:

1,对hibernate.cfg.xml进行建模,等到sessionfactory对象

2,并且拿到mapping resourse里的内容

3,拿到order.hbm.xml配置文件

4,可以再次建模,拿到实体类属性和对应的数据库表列段

5,生成动态的sql:select * 表名

执行sql最终得到meterData原数据模型

6,通过实体类进行反射 Class.forName(“com.zlk.three.entity.Order”).newInstance(0);

获得所有数据库内的数据。

最终得到List,且里面都有值(到这里只是处理了表里面的非外键列段)

7,处理关联关系 :通过标签获得orderItems(所有订单) oid 和订单实体类com.zlk.three.entity.OrderItem

然后通过one-to-many 里的 class(也就是com.zlk.three.entity.OrderItem),就可获得这个实体类的xml,

再通过这个xml获得对应的数据库表。

8,与第五步相同,最终获得了一个list

9,给order的关联关系属性赋值

就是在第六步中获得List时,一个一个的加进去:

for(Order o:List){

o.setOrderItems(List );

}

继续阅读