![7fe0b740dccd06a280003de20a7348da.png](https://img-blog.csdnimg.cn/img_convert/7fe0b740dccd06a280003de20a7348da.png)
前言:
上一篇文章我们学习了Hibernate的配置详解,主要包括两个配置文件,
hibernate.cfg.xml和hbm.xml。
今天继续来学习hbm.xml中两个重要的配置:
inverse和cascade。
1.inverse
在具体业务场景中,Customer和Orders是一对多关系,一个Customer对应多个Orders,实体类中用一个set集合作为属性来表示对应的Orders。
public class Customer { private int id; private String name; private Set orders; public int getId() { return id; } public void setId(int 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标签来配置映射关系。
<?xml version="1.0" encoding="UTF-8"?>
同理在Orders实体类中用一个Customer类型的属性来表示对应的Customer对象。
public class Orders { private int id; private String name; private Customer customer; public int getId() { return id; } public void setId(int 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标签来配置映射关系。
<?xml version="1.0" encoding="UTF-8"?>
从配置文件中可以看出,Customer和Orders是双向维护关系,即Customer在维护一对多关系,同时Orders也在维护一对多关系,在实际开发代码过程中,就可能会出现重复维护的情况。
创建一个Customer对象,创建两个Orders对象,并建立关联关系,Orders对象来维护一对多关系,代码如下。
//创建customer对象 Customer customer = new Customer(); customer.setName("张三"); //创建orders1对象 Orders orders1 = new Orders(); orders1.setName("订单1"); //将customer赋给orders1 orders1.setCustomer(customer); //创建orders2对象 Orders orders2 = new Orders(); orders2.setName("订单1"); //将customer赋给orders2 orders2.setCustomer(customer); //保存 session.save(customer); session.save(orders1); session.save(orders2); //提交事务 session.beginTransaction().commit(); //关闭session session.close();
执行代码,打印3条SQL语句,向customer表添加1条记录,向orders表添加2条记录,并且将customer的id值赋给cid字段,建立主外键约束关系。这段代码没有什么问题。
![aa2509ba8190a6d2aa2d2c8c27bb7a98.png](https://img-blog.csdnimg.cn/img_convert/aa2509ba8190a6d2aa2d2c8c27bb7a98.png)
此时修改Java代码,让Customer对象也来维护一对多关系。
//创建customer对象 Customer customer = new Customer(); customer.setName("张三"); //创建orders1对象 Orders orders1 = new Orders(); orders1.setName("订单1"); //将customer赋给orders1 orders1.setCustomer(customer); //创建orders2对象 Orders orders2 = new Orders(); orders2.setName("订单1"); //将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值赋给cid字段,建立主外键约束关系。
同时多了2条修改操作,再一次将customer的id值赋给cid字段,这2条SQL语句是在重复设置已经建立的主外键约束关系。
为什么会出现这种情况?
因为当前Customer和Orders对象都在维护关系,所以会重复建立两次主外键约束。
如何避免这种情况的出现呢?
第一种方式:在Java代码中去掉一方维护关系的代码。
第二种方式:通过设置hbm.xml文件来完成。
通常我们让多的一方来维护关系,即让Orders来维护,所以就需要让Customer放弃维护,在Customer.hbm.xml中设置set标签的inverse属性。
inverse属性是用来设置是否将维护权交给对方,默认为false,即不交出维护权,双方都在维护关系。
现在将invers设置为true,表示当前Customer已经放弃了维护权。
再次运行代码。
![b92231fbe1933deb0277905c20123621.png](https://img-blog.csdnimg.cn/img_convert/b92231fbe1933deb0277905c20123621.png)
![aa2509ba8190a6d2aa2d2c8c27bb7a98.png](https://img-blog.csdnimg.cn/img_convert/aa2509ba8190a6d2aa2d2c8c27bb7a98.png)
看到控制台打印3条SQL,即建立了一次主外键约束关系,并且是由Orders来维护的。
2.cascade:用来设置级联操作。
我们知道在删除一条主表数据时,一定要先清除被它约束的从表记录,
即在删除Customer对象时,必须先删除该对象对应的Orders对象,否则直接报错。
![ad329369fef92d784858955b60ae6d04.png](https://img-blog.csdnimg.cn/img_convert/ad329369fef92d784858955b60ae6d04.png)
![3b39b49d4583e810c0ce2f6e2e5b57ef.png](https://img-blog.csdnimg.cn/img_convert/3b39b49d4583e810c0ce2f6e2e5b57ef.png)
错误原因是因为被删除记录的主键正在约束orders表中的外键,必须先解除约束关系,才可删除。
如何解决?
第一种方式:修改Java代码,迭代Customer对象包含的所有Orders对象,将这些Orders对象全部删除,再删除Customer对象。
Customer customer = (Customer) session.get(Customer.class, 10); //迭代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时进行关联操作。
执行代码。
![a1866a15b3ea352e35101b82914dd271.png](https://img-blog.csdnimg.cn/img_convert/a1866a15b3ea352e35101b82914dd271.png)
会看到控制台会打印3条delete语句,前2条是删除Customer对象关联的2个Orders对象,第3条是删除Customer对象本身。
采用这种方式,我们不需要在逻辑代码中手动删除级联对象,Hibernate框架会自动帮我们删除这些对象。
关注微信公众号「Java大联盟」,关注即可获取海量学习干货,同时还有不定期送书,键盘,鼠标等粉丝福利。
![61ad28d0356c0dfb483b333a4ca4f002.png](https://img-blog.csdnimg.cn/img_convert/61ad28d0356c0dfb483b333a4ca4f002.png)
赶快来关注一波,海量资源拿到手软。