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-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 );
}
上一篇: JEECG Framework 3.5.0 GA 版本发布
下一篇: 这些雷女简直碉堡了