前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Hibernate配置文件详解-2

Hibernate配置文件详解-2

作者头像
南风
发布2019-04-22 17:14:57
5880
发布2019-04-22 17:14:57
举报
文章被收录于专栏:Java大联盟Java大联盟

前言:

上一篇文章我们学习了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> 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<Orders> getOrders() {
        return orders;
    }
    public void setOrders(Set<Orders> orders) {
        this.orders = orders;
    }
}

Customer.hbm.xml文件中用set标签来配置映射关系。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.southwind.entity">
    <class name="Customer" table="customer">
        <!-- 配置主键映射 -->
        <id name="id" type="java.lang.Integer">
            <column name="id"></column>
            <!-- 设置主键生成方式 -->
            <generator class="native"></generator>
        </id>

        <!-- 配置其他属性 -->
        <property name="name" type="java.lang.String">
            <column name="name"></column>
        </property>

        <set name="orders" table="orders">
            <!-- 配置外键 -->
            <key column="cid"></key>
            <one-to-many class="Orders"/>
        </set>
    </class>
</hibernate-mapping>

同理在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"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.southwind.entity">
    <class name="Orders" table="orders">
        <!-- 配置主键映射 -->
        <id name="id" type="java.lang.Integer">
            <column name="id"></column>
            <!-- 设置主键生成方式 -->
            <generator class="native"></generator>
        </id>

        <!-- 配置其他属性 -->
        <property name="name" type="java.lang.String">
            <column name="name"></column>
        </property>

        <many-to-one name="customer" class="Customer" column="cid"></many-to-one>
    </class>
</hibernate-mapping>

从配置文件中可以看出,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字段,建立主外键约束关系。这段代码没有什么问题。

此时修改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<Orders> ordersSet = new HashSet<Orders>();
        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已经放弃了维护权。

<set name="orders" table="orders" inverse="true">
    <!-- 配置外键 -->
    <key column="cid"></key>
    <one-to-many class="Orders"/>
</set>

再次运行代码。

看到控制台打印3条SQL,即建立了一次主外键约束关系,并且是由Orders来维护的。

2.cascade:用来设置级联操作。

我们知道在删除一条主表数据时,一定要先清除被它约束的从表记录,

即在删除Customer对象时,必须先删除该对象对应的Orders对象,否则直接报错。

错误原因是因为被删除记录的主键正在约束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时进行关联操作。

<set name="orders" table="orders" inverse="true" cascade="delete">
    <!-- 配置外键 -->
    <key column="cid"></key>
    <one-to-many class="Orders"/>
</set>

执行代码。

会看到控制台会打印3条delete语句,前2条是删除Customer对象关联的2个Orders对象,第3条是删除Customer对象本身。

采用这种方式,我们不需要在逻辑代码中手动删除级联对象,Hibernate框架会自动帮我们删除这些对象。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-01-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java大联盟 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档