我们以客户(Customer)与订单(Order)为例

实体类创建

Order订单实体类

//订单-----多的一方
public class Order {

    private Integer id;
    private Double money;
    private String receiverInfo; // 收货地址
    // 订单与客户关联
    private Customer c; // 描述订单属于某一个客户

    public Customer getC() {
        return c;
    }

    public void setC(Customer c) {
        this.c = c;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    public String getReceiverInfo() {
        return receiverInfo;
    }

    public void setReceiverInfo(String receiverInfo) {
        this.receiverInfo = receiverInfo;
    }

}

Customer客户实体类

//客户 ------一的一方
public class Customer {

    private Integer id; // 主键
    private String name; // 姓名

    // 描述客户可以有多个订单
    private Set<Order> orders = new HashSet<Order>();

    public Set<Order> getOrders() {
        return orders;
    }

    public void setOrders(Set<Order> orders) {
        this.orders = 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;
    }

}

Hbm映射文件编写

Order.hbm.xml配置文件

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

<hibernate-mapping>

    <class name="cn.nwtxxb.oneToMany.Order" table="t_order">
        <id name="id" column="c_id">
            <generator class="identity" />
        </id>
        <property name="money" column="c_money" />
        <property name="receiverInfo" column="c_receiverInfo" length="50"/>

        <!-- 多对一 -->
        <many-to-one fetch="join" lazy="false" name="c" class="cn.nwtxxb.oneToMany.Customer" column="c_customer_id">
        </many-to-one>
        <!-- 
            name属性它描述的是Order类中的一的一方的属性名称   Customer c;
            class 代表一的一方的类型
            column 描述的是一对多,在多的一方产生的外键的名称 c_customer_id
         -->
    </class>

</hibernate-mapping>

Customer.hbm.xml

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

<hibernate-mapping>

    <class name="cn.nwtxxb.oneToMany.Customer" table="t_customer">
        <id name="id" column="c_id">
            <generator class="identity" />
        </id>
        <property name="name" column="c_name" length="20" />

        <!-- 一个客户关联多个订单 -->
        <set name="orders" inverse="true" cascade="save-update">
            <key column="c_customer_id" />
            <one-to-many class="cn.nwtxxb.oneToMany.Order" />
        </set>

        <!-- 使用set来描述在一的一方中关联的多 Set<Order>,它的name属性就是set集合的名称 key:它主要描述关联的多的一方产生的外键名称,注意要与多的一方定义的外键名称相同 
            one-to-many 描述集合中的类型 -->
    </class>
</hibernate-mapping>

测试保存

public class OneToManyTest {
    // 测试保存
    @Test
    public void test1() {

        // 1.得到session
        Session session = HibernateUtils.openSession();
        session.beginTransaction();

        // 2.操作
        // 2.1创建一个客户
        Customer c = new Customer();
        c.setName("张三");

        // 2.2创建两个订单
        Order o1 = new Order();
        o1.setMoney(1000d);
        o1.setReceiverInfo("北京");

        Order o2 = new Order();
        o2.setMoney(2000d);
        o2.setReceiverInfo("上海");

        // 2.3建立关系
        // 2.3.1 订单关联客户
        o1.setC(c);
        o2.setC(c);
        // 2.3.2 客户关联订单
        c.getOrders().add(o1);
        c.getOrders().add(o2);

        session.save(o1);
        session.save(o2);
        session.save(c);

        // 3.事务提交,关闭
        session.getTransaction().commit();
        session.close();
    }
}

上面操作是一种双向关联
问题:我们可不可以只保存订单或只保存客户完成保存操作?

测试单向关联保存

// 测试保存---单向操作(保存订单并自动保存客户)
    @Test
    public void test2() {

        // 1.得到session
        Session session = HibernateUtils.openSession();
        session.beginTransaction();

        // 2.操作
        // 2.1创建一个客户
        Customer c = new Customer();
        c.setName("张三");

        // 2.2创建两个订单
        Order o1 = new Order();
        o1.setMoney(1000d);
        o1.setReceiverInfo("北京");

        Order o2 = new Order();
        o2.setMoney(2000d);
        o2.setReceiverInfo("上海");

        // 2.3建立关系

        // 2.3.1 订单关联客户
        o1.setC(c);
        o2.setC(c);

        session.save(o1); // o1是一个持久化对象
        session.save(o2); // o2是一个持久化对象

        // 3.事务提交,关闭
        session.getTransaction().commit();
        session.close();
    }

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: cn.nwtxxb.oneToMany.Customer
…………..
这个异常代表提一个持久化对象关联了一个瞬时对象。
我们可以使用级联操作来解决上述的问题.
我们现在要做的是保存订单时保存客户,需要在订单的hbm配置文件中修改

<!-- 多对一 -->
<many-to-one name="c" class="cn.nwtxxb.oneToMany.Customer" column="c_customer_id" cascade="save-update">
</many-to-one>

设置cascade=save-update 那么在保存订单时就可以自动将客户保存。
如果我们要完成保存客户时,保存订单

<!-- 一个客户关联多个订单 -->
<set name="orders" cascade="save-update">
    <key column="c_customer_id" />
    <one-to-many class="cn.nwtxxb.oneToMany.Order" />
</set>

双向关联保存

我们在开发中要配置双向关联配置。———可以通过任意一方来操作对方
在操作代码,尽量来要进行单向关联。——可以尽量资源浪费。
在双向关联中,会存在多余的update语句。
我们可以使用inverse属性来设置,双向关联时由哪一方来维护表与表之间的关系。

<!-- 一个客户关联多个订单 -->
<set name="orders" inverse="true" cascade="save-update">
    <key column="c_customer_id" />
    <one-to-many class="cn.nwtxxb.oneToMany.Order" />
</set>

Inverse它的值如果为true代表,由对方来维护外键。
Inverse它的值如果为false代表,由本方来维护外键。
关于inverse的取值:
外键在哪一个表中,我们就让哪一方来维护外键。

对象导航
Hibernate一对多关联映射及cascade级联操作_外键

级联删除

我们在删除客户时,也要删除订单,如果没有做级联,那么这个操作是不允许。
为了维护数据完整性

Hibernate一对多关联映射及cascade级联操作_hibernate_02

<!-- 一个客户关联多个订单 -->
<set name="orders" inverse="true" cascade="delete">
    <key column="c_customer_id" />
    <one-to-many class="cn.nwtxxb.oneToMany.Order" />
</set>

delete-orphan用法

Hibernate一对多关联映射及cascade级联操作_hibernate_03

<!-- 一个客户关联多个订单 -->
<set name="orders" inverse="true" cascade="delete-orphan">
    <key column="c_customer_id" />
    <one-to-many class="cn.nwtxxb.oneToMany.Order" />
</set>

测试类

public class OneToManyTest {

    // 级联 cascade= delete-orphan
    @Test
    public void test6() {
        // 1.得到session
        Session session = HibernateUtils.openSession();
        session.beginTransaction();

        // 2.操作
        // 得到客户
        Customer c = session.get(Customer.class, 2);
        // 得到客户的订单
        Order o = session.get(Order.class, 6);

        c.getOrders().remove(o);

        // 3.事务提交,关闭
        session.getTransaction().commit();
        session.close();
    }

    // 测试级联删除
    @Test
    public void test5() {
        // 1.得到session
        Session session = HibernateUtils.openSession();
        session.beginTransaction();

        // 操作----删除订单时,不需要删除客户,当我们删除一个客户时,应该将客户对应订单也删除。
        Customer c = session.get(Customer.class, 1);
        session.delete(c);// 删除客户?订单是否会删除?

        // 3.事务提交,关闭
        session.getTransaction().commit();
        session.close();

    }

    // 测试一对多对象导航
    @Test
    public void test4() {
        // 1.得到session
        Session session = HibernateUtils.openSession();
        session.beginTransaction();

        // 操作
        // 2.1创建一个客户
        Customer c = new Customer();
        c.setName("张三");

        // 2.2创建两个订单
        Order o1 = new Order();
        o1.setMoney(1000d);
        o1.setReceiverInfo("北京");

        Order o2 = new Order();
        o2.setMoney(2000d);
        o2.setReceiverInfo("上海");

        Order o3 = new Order();
        o3.setMoney(3000d);
        o3.setReceiverInfo("深圳");

        // 描述关系
        // o1要关联c

        o1.setC(c);
        // c要关联o2 o3
        c.getOrders().add(o2);
        c.getOrders().add(o3);

        session.save(o1);

        // 3.事务提交,关闭
        session.getTransaction().commit();
        session.close();
    }

    // 测试保存---单向操作(保存客户并自动保存订单)
    @Test
    public void test3() {

        // 1.得到session
        Session session = HibernateUtils.openSession();
        session.beginTransaction();

        // 2.操作
        // 2.1创建一个客户
        Customer c = new Customer();
        c.setName("张三");

        // 2.2创建两个订单
        Order o1 = new Order();
        o1.setMoney(1000d);
        o1.setReceiverInfo("北京");

        Order o2 = new Order();
        o2.setMoney(2000d);
        o2.setReceiverInfo("上海");

        // 2.3建立关系

        // 2.3.1 客户与订单关联
        c.getOrders().add(o1);
        c.getOrders().add(o2);

        session.save(c);// 保存客户

        // 3.事务提交,关闭
        session.getTransaction().commit();
        session.close();
    }

    // 测试保存---单向操作(保存订单并自动保存客户)
    @Test
    public void test2() {

        // 1.得到session
        Session session = HibernateUtils.openSession();
        session.beginTransaction();

        // 2.操作
        // 2.1创建一个客户
        Customer c = new Customer();
        c.setName("张三");

        // 2.2创建两个订单
        Order o1 = new Order();
        o1.setMoney(1000d);
        o1.setReceiverInfo("北京");

        Order o2 = new Order();
        o2.setMoney(2000d);
        o2.setReceiverInfo("上海");

        // 2.3建立关系

        // 2.3.1 订单关联客户
        o1.setC(c);
        o2.setC(c);

        session.save(o1); // o1是一个持久化对象
        session.save(o2); // o2是一个持久化对象

        // 3.事务提交,关闭
        session.getTransaction().commit();
        session.close();
    }

    // 测试保存
    @Test
    public void test1() {

        // 1.得到session
        Session session = HibernateUtils.openSession();
        session.beginTransaction();

        // 2.操作
        // 2.1创建一个客户
        Customer c = new Customer();
        c.setName("张三");

        // 2.2创建两个订单
        Order o1 = new Order();
        o1.setMoney(1000d);
        o1.setReceiverInfo("北京");

        Order o2 = new Order();
        o2.setMoney(2000d);
        o2.setReceiverInfo("上海");

        // 2.3建立关系
        // 2.3.1 订单关联客户
        o1.setC(c);
        o2.setC(c);
        // 2.3.2 客户关联订单
        c.getOrders().add(o1);
        c.getOrders().add(o2);

        session.save(o1);
        session.save(o2);
        session.save(c);

        // 3.事务提交,关闭
        session.getTransaction().commit();
        session.close();
    }
}

HibernateUtils工具类

public class HibernateUtils {

    private static Configuration config;
    private static SessionFactory sessionFactory;

    static{

        config=new Configuration().configure();
        sessionFactory=config.buildSessionFactory();
    }

    public static Session openSession(){
        return sessionFactory.openSession();
    }
}

cascade级联操作总结

使用cascade可以完成级联操作
它可常用取值:
none这是一个默认值
save-update,当我们配置它时,底层使用save update或save-update完成操作,级联保存临时对象,如果是游离对象,会执行update.
delete 级联删除
delete-ophan 删除与当前对象解除关系的对象。
all 它包含了save-update delete操作
all-delete-orphan 它包信了delete-orphan与all操作
问题:cascade与inverse有什么区别?
cascade它是完成级联操作
Inverse它只有在双向关联情况下有作用,它来指定由哪一方维护外键。