前言:
上一篇文章我们学习了Hibernate的配置详解,主要包括两个配置文件,
hibernate.cfg.xml和hbm.xml。
今天继续来学习hbm.xml中两个重要的配置:
inverse和cascade。
1.inverse
在具体业务场景中,Customer和Orders是一对多关系,一个Customer对应多个Orders,实体类中用一个set集合作为属性来表示对应的Orders。
public class Customer implements Serializable {
private Integer id;
private String name;
private Set orders;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set getOrders() {
return orders;
}
public void setOrders(Set orders) {
this.orders = orders;
}
}
Customer.hbm.xml文件中用set标签来配置映射关系。
同理在Orders实体类中用一个Customer类型的属性来表示对应的Customer对象。
public class Orders implements Serializable {
private Integer id;
private String name;
private Customer customer;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
Orders.hbm.xml中,用many-to-one标签来配置映射关系。
从配置文件中可以看出,Customer和Orders是双向维护关系,即Customer在维护一对多关系,同时Orders也在维护一对多关系,在实际开发代码过程中,就可能会出现重复维护的情况。
创建一个Customer对象,创建两个Orders对象,并建立关联关系,Orders对象来维护一对多关系,代码如下。
//4.创建Session对象
Session session = sessionFactory.openSession();
//5.创建Customer对象
Customer customer = new Customer();
customer.setName("张三");
//6.创建Orders对象
Orders orders = new Orders();
orders.setName("订单1");
Orders orders2 = new Orders();
orders2.setName("订单2");
//7.建立关联关系
orders.setCustomer(customer);
orders2.setCustomer(customer);
//8.保存
session.save(customer);
session.save(orders);
session.save(orders2);
//9.提交事务
session.beginTransaction().commit();
//10.关闭session
session.close();
执行代码,打印3条SQL语句,向customer表添加1条记录,向orders表添加2条记录,并且将customer的id值赋给oid字段,建立主外键约束关系。这段代码没有什么问题。
此时修改Java代码,让Customer对象也来维护一对多关系。
//创建customer对象
Customer customer = new Customer();
customer.setName("李四");
//创建orders1对象
Orders orders1 = new Orders();
orders1.setName("订单3");
//将customer赋给orders1
orders1.setCustomer(customer);
//创建orders2对象
Orders orders2 = new Orders();
orders2.setName("订单4");
//将customer赋给orders2
orders2.setCustomer(customer);
//创建集合,将orders1,orders2加入集合
Set ordersSet = new HashSet();
ordersSet.add(orders1);
ordersSet.add(orders2);
//将Orders集合赋给customer
customer.setOrders(ordersSet);
//保存
session.save(customer);
session.save(orders1);
session.save(orders2);
//提交事务
session.beginTransaction().commit();
//关闭session
session.close();
再次执行代码,打印5条SQL,向customer表添加1条记录,向orders表添加2条记录,并且将customer的id值赋给oid字段,建立主外键约束关系。
同时多了2条修改操作,再一次将customer的id值赋给oid字段,这2条SQL语句是在重复设置已经建立的主外键约束关系。
为什么会出现这种情况?
因为当前Customer和Orders对象都在维护关系,所以会重复建立两次主外键约束。
如何避免这种情况的出现呢?
第一种方式:在Java代码中去掉一方维护关系的代码。
第二种方式:通过设置hbm.xml文件来完成。
通常我们让多的一方来维护关系,即让Orders来维护,所以就需要让Customer放弃维护,在Customer.hbm.xml中设置set标签的inverse属性。
inverse属性是用来设置是否将维护权交给对方,默认为false,即不交出维护权,双方都在维护关系。
现在将invers设置为true,表示当前Customer已经放弃了维护权。
再次运行代码。
看到控制台打印3条SQL,即建立了一次主外键约束关系,并且是由Orders来维护的。
2.cascade:用来设置级联操作。
我们知道在删除一条主表数据时,一定要先清除被它约束的从表记录,
即在删除Customer对象时,必须先删除该对象对应的Orders对象,否则直接报错。
错误原因是因为被删除记录的主键正在约束orders表中的外键,必须先解除约束关系,才可删除。
如何解决?
第一种方式:修改Java代码,迭代Customer对象包含的所有Orders对象,将这些Orders对象全部删除,再删除Customer对象。
Customer customer = (Customer) session.get(Customer.class, 2);
//迭代orders集合
Iterator iter = customer.getOrders().iterator();
while(iter.hasNext()){
Orders orders = (Orders) iter.next();
//删除orders对象
session.delete(orders);
}
session.delete(customer);
session.beginTransaction().commit();
session.close();
第二种方式:不需要修改Java代码,在hbm.xml中设置级联删除属性即可,设置cascade="delete"。
cascad:有4个值可以选择。
1.all : 所有情况下均进行关联操作。
2.none:所有情况下均不进行关联操作。这是默认值。
3.save-update:在执行save/update/saveOrUpdate时进行关联操作。
4.delete:在执行delete时进行关联操作。
执行代码。
会看到控制台会打印3条delete语句,前2条是删除Customer对象关联的2个Orders对象,第3条是删除Customer对象本身。
采用这种方式,我们不需要在逻辑代码中手动删除级联对象,Hibernate框架会自动帮我们删除这些对象。