精通Hibernate——建立双向一对多关联

当类与类之间建立了关联,就可以方便的从一个对象导航到另一个对象或者一组与他关联的对象。

对象位于内存中,在内存中从一个对象导航到另一个对象显然比到数据库中查询数据速度快多了。类与类之间到底建立双向还是单向都是由业务决定。以Customer和Order为例,如果软件应用有大量这样的需求:

根据客户可以查询该客户所有的订单

根据给定的订单可以查询发出订单的客户

以上需求就需要我们为Customer和Order类创建双向关联,代码如下:

public class Customer{
    private Set orders = new HashSet();

    public Set getOrders(){
        return orders;
    }

    public void setOrders(Set orders){
        this.orders = orders;
    }
}

有了以上属性,当Customer查询订单时候只需要调用customer.getOrders()方法即可。Hibernate要求在持久化类中定义集合属性,必须把属性定义为接口类型如:java.util.Map,java.util.ArrayList,java.util.Set等,这样可以提供Hibernate持久化类的透明性。

在定义orders集合属性时,通常把它初始化为集合实现类的一个实例,例如:

private Set orders = new HashSet();

这样可以提供程序的健壮性,避免orders中没有任何东西时也不会抛出NullPointException,例如:

Set orders = new HashSet();
Iterator it = orders.iterator();
while(it.hasNext()){
    // do something
}

下面我们说一下如何在配置文件中映射集合类型的orders属性,配置代码如下:

<set name="orders" cascade="save-update">
    <key column="CUSTOMER_ID" />
    <one-to-many class="com.fyw.Orders" />
</set>

下面分别介绍下一些保存操作:

(1)saveCustomerAndOrdersWithCaseCade():该方法用于当set的casecade属性配置为save-update时Hibernate的运行时行为:

tx = session.beginTransaction();
Customer customer = new Customer("tom",new HashSet());
Order order = new Order();
order.setOrderNumber("tom_order001");
// 建立Customer与Orders对象的双向关联
order.setCustomer(customer);
customer.getOrders().add(order);
session.save(customer);
tx.commit();

(2)saveCustomerAndOrderWithInverse():该方法会依次调用下面两个方法

saveCustomerAndOrderSeparately()

先创建一个Customer对象和一个Order对象,不建立它们的关联关系,最后分别持久化这两个对象:

tx = session.beginTransaction();
Customer customer = new Customer();
customer.setName("Jack");
Orders order = new Orders();
order.setOrderNumber("Jack_order001");
session.save(customer);
session.save(order);
tx.commit();

为了使以上代码运行正常需要将Order.hbm.xml文件中one-to-many元素的not-null属性设置为false,否则会因为违反参照完整性约束而产生异常

associateCustomerAndOrder()

该方法加载被saveCustomerAndOrderSeparately()方法持久化的Customer和Order对象,然后建立两者两者一对多的双向关联关系:

tx = session.beginTransaction();
// 加载持久化对象
Customer customer = (Customer)session.load(Customer.class,new Long(2));
Order order = (Order)session.load(Order.class,new Long(2));
// 建立Customer和Orders的双向关联
order.setCustomer(customer);
customer.getOrders().add(order);
tx.commit();

Hibernate会自动清理缓存中的所有持久化对象,按照持久化对象状态的改变来同步更新数据库,此时Hibernate在清理以上Customer对象和Order对象时执行了以下两条sql语句:

update orders set order_numbers = ‘Jack_order001‘,customer_id=2 where id = 2;
update orders set customer_id=2 where id = 2;

尽管只是修改了Orders表的一条记录,但是执行两次SQL,这是因为Hibernate根据内存中持久化对象的状态变化类决定需要执行哪些sql语句

order.setCustomer(customer);会执行

update orders set order_numbers = ‘Jack_order001‘,customer_id=2 where id = 2;
customer.getOrders().addOrder(order);会执行:
update orders set customer_id = 2 where id = 2;

重复执行多余的sql会影响Hibernate的性能,解决这一问题的办法是将inverse属性配置为true,默认为false.

<set name="orders" cascade="save-update" inverse="true">
    <key column="CUSTOMER_ID" />
    <one-to-many class="com.fyw.Orders" />
</set>

以上代码表明在Customer和Order双向关联关系中,Customer的关联只是Order端关联的镜像,当Hibernate探测到持久化对象Customer和Order状态均发生变化时,仅按照Order对象状态变化来同步更新数据库,因此我们可以将associateCustomerAndOrder()改为:

tx = session.beginTransaction();
// 加载持久化对象
Customer customer = (Customer)session.load(Customer.class,new Long(2));
Order order = (Order)session.load(Order.class,new Long(2));
// order.setCustomer(customer);
customer.getOrders().add(order);
tx.commit();

以上代码仅设置了Customer对象的Order属性,由于set的inverse属性为true,因此Hibernate不会按照Customer对象的状态变化来同步更新数据库。

因此:

1.在映射一对多的双向关联关系时,应该在many方把inverse属性设为true,这样可以提高性能

2.在建立两个对象的双向关联时,应该同时修改关联两端的对象的相应属性

级联删除

在deleteCustomer()方法中,先加载一个Customer对象,然后删除这个对象

tx = session.beginTransaction();
Customer customer = (Customer)session.load(Customer.class,new Long(1));
session.delete(customer);
tx.commit();

当cascase属性取默认值none时,不会执行级联删除,除非配置为cascade属性设置delete

<set name="orders" cascade="delete" inverse="true">
    <key column="CUSTOMER_ID" />
    <one-to-many class="com.fyw.Orders" />
</set>

casecade还有一个all-delete-orphan属性,含义为:

当保存或者更新Customer对象时,相当于cascade=’save-udpate’,当删除Customer对象时相当于cascade=”delete”

删除不再和Customer对象关联的所有的Order对象

时间: 2025-01-01 21:27:21

精通Hibernate——建立双向一对多关联的相关文章

精通Hibernate——建立单向多对一关联

在类与类之间各种各样的关系中,要算多对一的单向关联关系和关系数据库中的外键参照关系最匹配了.因此,通常选择从Order到Customer的多对一单向关联.简要代码如下: public class Customer implements Serializable{ private Long id; private String name; .... } public class Order implements Serializable{ private Long id; private Stri

Hibernate实现双向一对多,多对一

人与电话号码是一对多 ,多对一的关系 @Entity @Table(name="tb_person") public class Person { @Id @GeneratedValue(strategy = GenerationType.AUTO) private int id; private String name; @OneToMany(mappedBy = "person") /*在双向一对多关系中 将控制权交给“多”方 */ private List&l

hibernate一对一双向外键关联

一对一双向外键关联:双方都持有对方的外键关联关系. 主控方和一对一单向外键关联的情况是一样的,主要的差异表现为,被空方需要添加: @OneToOne(mappedBy="card") //被控方 主控方必须交给其中的一方去控制,因为不可以双方都同时拥有控制对方的权利,假如是这样的话是没有办法保存成功的.这就是为什么需要指定mappenBy="card"的原因. 1.IdCard.java实体类: package oto_bfk; import javax.persi

hibernate 之 关联映射的双向一对多关联

1. 考虑学生表 和 教师表,表结构和单向的表结构一样. 2. 类结构:Teacher.java public class Teacher { private int id; private String name; private Set<Student> students = new HashSet<Student>(); public Teacher() { } public Teacher(String name) { super(); this.name = name;

Hibernate 配置 双向 对多关联 (未完待续&#183;&#183;&#183;&#183;&#183;&#183;&#183;)

               从生疏到熟练  是要经历多少遍的练习? 这答案只能向自己找. 以Student和Course为例,一个学生可以选多门课程,一门课程也可以被多个学生选取: 首先  我们创建持久化类Student 1 package bean; 2 3 import java.util.Set; 4 5 public class Student { 6 private long id; 7 private String name;//学生姓名 8 private Set<Course>

hibernate中配置单向多对一关联,和双向一对多

什么是一对多,多对一?双向多对一和双向一对多是不是同一个概念? 是一个概念,双向多对一和双向一对多都是配置一个 一对多和多对一 一对多,比如你去找一个父亲的所有孩子,孩子可能有两个,三个甚至四个孩子. 这就是一对多 父亲是1 孩子是多 多对一,比如你到了两个孩子,它们都是有一个共同的父亲. 此时孩子就是多 父亲是1  总结: 一对多就是: 1找到n 多对一就是: n找到1 有些人写概念写一大堆搞起我之前是一脸懵逼,还好弄懂了(手动滑稽) 配置单向多对一 通过上面我们可以了解,双向一对多是 1找n

4.一对多关联映射

1.实体一对多关联 一对多联系(1:n)定义:如果对于实体集A中的每一个实体,实体集B中有n个实体(n≥0)与之联系,反之,对于实体集B中的每一个实体,实体集A中至多只有一个实体与之联系,则称实体集A与实体集B有一对多联系,记为1:n.实例:一个班级中有若干名学生,每个学生只在一个班级中学习. 2.数据库一对多关联 在关系模型中,只存在外键参照关系,而且是 many 方参照 one 方. 3.Hibernate单向一对多关联 在关系模型中,只存在外键参照关系,而且是 many 方参照 one 方

双向一对多

1.在一的一方实体类里添加多的一方的集合 public class Dept { private Integer deptNo; private String deptName; //加入员工集合 private Set<Emp> emps=new HashSet<Emp>(); public Set<Emp> getEmps() { return emps; } public void setEmps(Set<Emp> emps) { this.emps

Hibernate5.2关联关系之双向一对多(三)

                                                       Hibernate之双向一对多(三) 一.简介 本篇博文接着上一章的内容接着开展,代码也是在上篇博文的基础上修改. 二.hbm文件的方式 Customer.hbm.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hi