时间:2017-1-20 16:28

——一对多配置

1、第一步:创建实体类
    *   客户实体
    *   订单实体

    示例代码:
        /**

         * 客户实体
         * @author WYC
         *
         */
        public class Customer {
            private Integer cid;
            private String name;
 
            // 一个客户有多个订单
            // 拥有哪些订单 
            private Set<Order> orders = new HashSet<Order>();
            set() / get()... 
        }

        /**
         * 订单实体
         * @author WYC
         *
         */
        public class Order {
            private Integer oid;
            private String addr;
 
            // 订单属于某一个客户
            private Customer customer;
            set() / get()...
        }

2、第二步:建立映射

    1)Customer的映射

        <hibernate-mapping>
            <class name="com.wyc.hibernate3.demo2.Customer" table="customer">
                <id name="cid" column="cid">
                    <generator class="native"/>
                </id>
 
                <property name="cname" column="cname" length="20"/>
 
 
                <!-- 配置映射 -->
                <!-- 因为属性是一个集合,所以需要配置集合 -->
                <!-- name:Customer对象中关联对象的属性名称 -->
                <set name="orders">
                    <!-- key标签中的column用来描述一对多关系中多的一方的外键的名称 -->
                    <key column="cid"></key>
                    <!-- 配置一个<one-to-many>,用来指定多的一方的实体类 -->
                    <one-to-many class="com.wyc.hibernate3.demo2.Order"/>
                </set>
            </class>
        </hibernate-mapping>

2)Order的映射

        <hibernate-mapping>
            <class name="com.wyc.hibernate3.demo2.Order" table="order_table">
                <id name="oid" column="oid">
                    <generator class="native"/>
                </id>
 
                <property name="addr" column="addr" length="50"/>
 
                <!-- 配置映射 -->
                <!-- <many-to-one>标签
                    name:关联对象的属性名称
                    column:外键的名称
                    class:关联对象类的全路径
                 -->
                <many-to-one name="customer" column="cid" class="com.wyc.hibernate3.demo2.Customer" />
            </class>
        </hibernate-mapping>

one-to-many和many-to-one中的column必须一致,否则会创建两个外键。

3、第三步:将映射放到核心配置文件中

——一对多级联保存

级联:操作当前对象的时候,关联的对象如何处理?

1、通常情况下如果想要向数据库插入数据,需要每个对象都要save一次,例如:

    public class HibernateDemo2 {
        @Test
        // 向客户表插入一个客户,在订单表中插入两个订单
        public void fun1() {
            Session session = HibernateUtils.openSession();
 
            Transaction tx = session.beginTransaction();
 
            /*
             * 定义一个客户
             */
            Customer customer = new Customer();
            customer.setCname("张三");
 
            /*
             * 定义两个订单
             */
            Order order1 = new Order();
            order1.setAddr("奎文区");
            Order order2 = new Order();
            order2.setAddr("高新区");
 
            /*
             * 建立关系
             */
            order1.setCustomer(customer);
            order2.setCustomer(customer);
 
            customer.getOrders().add(order1);
            customer.getOrders().add(order2);
 
            session.save(customer);
            session.save(order1);
            session.save(order2);
 
            tx.commit();
            session.close();
        }
    }

2、能否只保存其中一个?从而完成保存两条数据
    可以使用级联保存。

    级联保存的方向性:
        *   保存客户时选择级联订单(在Customer中配置级联)
        *   保存订单的时候选择级联客户。(在Order中配置级联)

    不能直接save()其中一个持久态对象,否则会抛出异常:org.hibernate.TransientObjectException

3、级联保存示例代码

    /*
     * 保存订单,同时级联客户
     * 当保存订单时,需要关联Customer对象,所以需要在many-to-one上进行配置一个属性:
     *  cascade="save-update",表示在保存或更新时会级联操作
     */
    public void fun4(){
        Session session = HibernateUtils.openSession();
 
        Transaction tx = session.beginTransaction();
 
        /*
         * 定义一个客户
         */
        Customer customer = new Customer();
        customer.setCname("张三");
 
        /*
         * 定义一个订单
         */
        Order order1 = new Order();
        order1.setAddr("奎文区");
 
        /*
         * 建立关系
         */
        order1.setCustomer(customer);
        customer.getOrders().add(order1);
 
        /*
         * 只保存一方
         */
        session.save(order1);
 
        tx.commit();
        session.close();
    }
 
 
    /*
     * 保存客户,同时级联订单
     * 当保存客户时,需要关联Set集合,所以需要在Set集合上进行配置一个属性:
     *  cascade="save-update",表示在保存或更新时会级联操作
     */
    public void fun3(){
        Session session = HibernateUtils.openSession();
 
        Transaction tx = session.beginTransaction();
 
        /*
         * 定义一个客户
         */
        Customer customer = new Customer();
        customer.setCname("张三");
 
        /*
         * 定义一个订单
         */
        Order order1 = new Order();
        order1.setAddr("奎文区");
 
        /*
         * 建立关系
         */
        order1.setCustomer(customer);
        customer.getOrders().add(order1);
 
        /*
         * 只保存一方
         */
        session.save(customer);
 
        tx.commit();
        session.close();
    }

——一对多级联删除

1、不配置级联删除的情况下:
    示例代码:

        /*
         * 如果不配置级联删除,会将外键置为null,然后再删除记录
         */
        public void fun5(){
            Session session = HibernateUtils.openSession();
            Transaction tx = session.beginTransaction();
 
            /*
             * 删除客户
             * 如果想要级联删除,则必须先查询再删除
             */
            Customer customer = (Customer) session.get(Customer.class, 1);
 
            session.delete(customer);
 
            tx.commit();
            session.close();
        }

2、配置级联删除的情况下,删除客户的时候级联删除订单:

    需要在Customer.hbm.xml的<set>标签上配置cascade="delete",如果cascade有多个值,可以用逗号隔开。

    示例代码:

        /*
         * 级联删除
         */
        public void fun6(){
            Session session = HibernateUtils.openSession();
            Transaction tx = session.beginTransaction();
 
            /*
             * 级联删除:先查询,再删除
             */
 
            /*
             * 删除客户时级联删除订单
             * 在<set>标签中配置cascade="delete"
             */
            Customer customer = (Customer) session.get(Customer.class, 1);
            session.delete(customer);
 
            /*
             * 删除订单时级联删除客户
             * 需要在Order.hbm.xml中的many-to-one中配置cascade="delete"
             */
            Order order = (Order) session.get(Order.class, 1);
            session.delete(order);
 
            tx.commit();
            session.close();
        }

——cascade取值

1、none
    不使用级联,是默认值。

2、save-update
    保存或更新时级联。

3、delete
    删除时级联。

4、all
    除了孤儿删除以外所有的操作都会级联。

5、delete-orphan
    孤儿删除(孤子删除)
    仅限于一对多,因为只有一对多的时候才有主从(父子)关系存在。
    一的一方是主(父)方。
    多的一方是从(子)方。

    当一个客户与某个订单解除了关系时,相当于把订单的外键置为null,订单就没有了所属客户了,那么就会将这种记录删除。

    删除没有外键的记录。

6、all-delete-orphan
    包含了孤儿删除的所有级联操作。

7、孤儿删除示例代码:

    /*
     * 孤儿删除
     * 在Customer.hbm.xml中<set>标签上配置cascade="delete-orphan"
     */
    public void fun7(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
 
        /*
         * 让2号客户与2号订单解除关系
         */
        Customer customer = (Customer) session.get(Customer.class, 2);
        Order order = (Order) session.get(Order.class, 2);
 
        // 将该客户对应的其中某一订单删除后,该订单的外键就是null了
        customer.getOrders().remove(order);
 
 
        tx.commit();
        session.close();
    }

——双向维护 - 产生多余SQL

配置inverse="true",在哪一端配置,配置的那一端就放弃了外键的维护权。

示例代码:

    /*
     * 双向维护:自动更新数据库,会产生多余的SQL
     * 双方都有维护外键的能力,要想不产生多余SQL,必须让其中一方放弃外间的维护权:<set inverse="true">
     * 一般情况下都是“多”的一方维护外键关系
     */
    public void fun8(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
 
        /*
         * 将3号客户的订单改为1号客户的订单
         */
        Customer customer = (Customer) session.get(Customer.class, 1);
 
        Order order = (Order) session.get(Order.class, 3);
 
        /*
         * 持久态对象如果发生变化会自动更新数据库
         * 会发送两条update语句
         */
 
        customer.getOrders().add(order);
        order.setCustomer(customer);
 
        tx.commit();
        session.close();
    }

——cascade和inverse的区别

cascade:操作关联对象
inverse:控制外键的维护

示例代码:

    /*

     * 区分cascade和inverse
     * 
     * 在Customer.hbm.xml中配置:<set name="orders" cascade="save-update" inverse="true" >
     */
    public void fun9(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
 
        Customer customer = new Customer();
        customer.setCname("张三");
 
        Order order = new Order();
        order.setAddr("奎文");
 
        // 客户关联订单
        customer.getOrders().add(order);
 
        /*
         * 客户是否保存到数据库:保存
         * 订单是否保存到数据库:保存,因为设置了cascade="save-update",但是订单的外键是null
         * 因为在Customer中设置了inverse="true",说明外键不属于Customer来维护
         * 只有在插入订单时,才会产生外键 
         */
        session.save(customer);
 
        tx.commit();
        session.close();
    }

——多对多的配置

1、学生实体类

    public class Student {
        private Integer sid;
        private String sname;
        private Set<Course> courses = new HashSet<Course>();
 
        @Override
        public String toString() {
            return "Student [sid=" + sid + ", sname=" + sname + ", courses=" + courses + "]";
        }
 
        public Set<Course> getCourses() {
            return courses;
        }
 
        public void setCourses(Set<Course> courses) {
            this.courses = courses;
        }
 
        public Integer getSid() {
            return sid;
        }
 
        public void setSid(Integer sid) {
            this.sid = sid;
        }
 
        public String getSname() {
            return sname;
        }
 
        public void setSname(String sname) {
            this.sname = sname;
        }
}

2、课程实体类

    public class Course {
        private Integer cid;
        private String cname;
        private Set<Student> students = new HashSet<Student>();
 
        public Integer getCid() {
            return cid;
        }
 
        public void setCid(Integer cid) {
            this.cid = cid;
        }
 
        public String getCname() {
            return cname;
        }
 
        public void setCname(String cname) {
            this.cname = cname;
        }
 
        public Set<Student> getStudents() {
            return students;
        }
 
        public void setStudents(Set<Student> students) {
            this.students = students;
        }
}
 

3、Student.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="com.wyc.hibernate3.demo3.Student" table="student">
            <id name="sid" column="sid">
                <generator class="native"></generator>
            </id>
 
            <property name="sname" column="sname" length="20" />
 
            <!-- 配置关联映射 -->
            <!-- 多对多时存在中间表,table属性写中间表的名称,两个类中的table必须一致,否则生成多个中间表 -->
            <set name="courses" table="stu_cour">
                <!-- key标签中的column写本类在中间表中的外键字段 -->
                <key column="sid" />
                <!-- many-to-many中的class是另一方类的全路径,column表示另一方类在中间表中外键的名称 -->
                <many-to-many class="com.wyc.hibernate3.demo3.Course" column="cid"></many-to-many>
            </set>
 
        </class>
    </hibernate-mapping>

4、Course.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="com.wyc.hibernate3.demo3.Course" table="course">
            <id name="cid" column="cid">
                <generator class="native"></generator>
            </id>
 
            <property name="cname" column="cname" length="20" />
 
            <!-- 配置与学生关联的映射 -->
            <set name="students" table="stu_cour" inverse="true" >
                <key column="cid" />
                <many-to-many class="com.wyc.hibernate3.demo3.Student" column="sid"/>
            </set>
        </class>
     </hibernate-mapping>

5、将映射配置文件添加到核心配置文件中

——多对多的保存操作

如果在多对多的情况下进行保存,则必须有一方放弃主键维护,不然会导致主键重复。

通常是主动方来维护主键,比如学生选课,学生来维护主键。

需要在Course.hbm.xml中添加<set inverse="true">来指定Course放弃维护主键。

public class HibernateDemo3 {
    @Test
    /*
     * 保存学生和课程 为学生选择一些课程
     */
    public void fun1() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
 
        // 创建学生
        Student student1 = new Student();
        student1.setSname("张三");
 
        Student student2 = new Student();
        student2.setSname("李四");
 
        // 创建课程
        Course course1 = new Course();
        course1.setCname("Java");
 
        Course course2 = new Course();
        course2.setCname("Android");
 
        // 张三选择1号课程和2号课程
        student1.getCourses().add(course1);
        student1.getCourses().add(course2);
 
        course1.getStudents().add(student1);
        course2.getStudents().add(student1);
 
        // 李四选1号课程
        student2.getCourses().add(course1);
        course1.getStudents().add(student2);
 
        // 执行保存
        session.save(student1);
        session.save(student2);
 
        session.save(course1);
        session.save(course2);
 
        tx.commit();
        session.close();
    }
}

——多对多级联保存

/*
 * 级联操作:保存学生,关联课程
 * 在Student.hbm.xml中配置cascade="save-update"
 */
public void fun2() {
    Session session = HibernateUtils.openSession();
    Transaction tx = session.beginTransaction();
 
    // 创建学生
    Student student = new Student();
    student.setSname("王五");
 
    // 创建课程
    Course course = new Course();
    course.setCname("PHP");
 
    student.getCourses().add(course);
    course.getStudents().add(student);
 
 
    session.save(student);
 
    tx.commit();
    session.close();
}

——删除中间表信息

获取中间表后将记录从集合中删除即可。

/*
 * 删除1号学生的选课信息
 */
public void fun3() {
    Session session = HibernateUtils.openSession();
    Transaction tx = session.beginTransaction();
 
    // 查询1号学生
    Student student = (Student) session.get(Student.class, 1);
 
    // 查询1号课程
    Course course = (Course) session.get(Course.class, 1);
 
    // 删除选课信息
    student.getCourses().remove(course);
 
    tx.commit();
    session.close();
}

——总结

1、一对一的配置
    *   在多的一方:<many-to-one>
    *   在一的一方:<set> <key /> <one-to-many> </set>
2、多对多的配置
    *   <set> <key /> <many-to-many /> </set>
    在多对多关系的情况下,需要有一方放弃外键维护权。
3、级联操作
    *    save-update
    *   delete
    *   all
    *   delete-orphan(孤儿删除)
    *   all-delete-orphan
4、inverse
    放弃外键维护权
    通常在一的一方放弃。

Hibernate之关联关系的更多相关文章

  1. hibernate有关联关系删除子表时可能会报错,可以用个clear避免错误

    //清除子表数据 public SalesSet removeSalesSetDistributor(SalesSet salesSet ){ List<SalesSetDistributor& ...

  2. Hibernate之关联关系映射(一对一主键映射和一对一外键映射)

    1:Hibernate的关联关系映射的一对一外键映射: 1.1:第一首先引包,省略 1.2:第二创建实体类: 这里使用用户信息和身份证信息的关系,用户的主键编号既可以做身份证信息的主键又可以做身份证信 ...

  3. Hibernate JPA 关联关系

    Hibernate JPA 关联关系: 使用cascade做级联操作(只有在满足数据库约束时才会生效): CascadeType.PERSIST: 级联保存,只有调用persist()方法,才会级联保 ...

  4. Hibernate 一对一关联关系

    双向一对一关联关系: 域模型: 例如,部门只有一个部门经理,一个经理也只能管理一个部门.即,Department 中有一个Manager的引用,Manager 中又有一个Department 的引用. ...

  5. 框架之 hibernate之关联关系映射

    案例:完成CRM的联系人的保存操作 需求分析 1. 因为客户和联系人是一对多的关系,在有客户的情况下,完成联系人的添加保存操作 技术分析之Hibernate的关联关系映射之一对多映射(重点) 1. J ...

  6. Hibernate的关联关系映射

    技术分析之Hibernate的关联关系映射之一对多映射(重点)        1. JavaWEB中一对多的设计及其建表原则        2. 先导入SQL的建表语句                 ...

  7. Hibernate —— 映射关联关系

    一.映射多对一关联关系. 1.单向的多对一 (1)以 Customer 和 Order 为例:一个用户可以发出多个订单,而一个订单只能属于一个客户.从 Order 到 Customer 是多对一关联关 ...

  8. Hibernate 实体关联关系映射【转】

    Hibernate关联关系映射目录│ ├─单向关联│  ├─  一对一外键单向关联│  ├─  一对一主键单向关联│  ├─  一对一连接表单向关联│  ├─  一对多外键单向关联│  ├─  一对多 ...

  9. Hibernate笔记——关联关系配置(一对多、一对一和多对多)

    原文:http://www.cnblogs.com/otomedaybreak/archive/2012/01/20/2327695.html ============================ ...

  10. Hibernate三 关联关系

    Hibernate的关联映射 客观世界中很少有对象是独立存在的,比如我们可以通过某个老师获取该老师教的所有学生,我们也可以通过某个学生获得教他的对应的老师,实体之间的互相访问就是关联关系.在Hiber ...

随机推荐

  1. 在 Intenseye,为什么我们选择 Linkerd2 作为 Service Mesh 工具(Part.2)

    在我们 service mesh 之旅的第一部分中,我们讨论了"什么是服务网格以及我们为什么选择 Linkerd2?".在第二部分,我们将讨论我们面临的问题以及我们如何解决这些问题 ...

  2. 单机版kafka的安装

    简单记录单机版kafka的安装:JDK1.8(jdk-8u131-linux-x64.rpm)zookeeper (zookeeper-3.4.10.tar.gz)kafka (kafka_2.12- ...

  3. EF中数据修改时动态更新其他数据

    场景 利用.net core开发时,经常会遇到使用EF(Entity Framework),但是今天在开发过程中发现一个值莫名其妙的自己变了,我怀疑是EF的问题. 主要代码如下: 1 // 最近一条告 ...

  4. 为MySQL的source命令导入SQL文件配置参数

    为MySQL的source命令导入SQL文件配置参数 执行 mysql -uroot -p 输入密码后进入 MySQL 命令提示符 set charset utf8; source /root/xxx ...

  5. RHCE_DAY03

    shell函数 在shell环境中,将一些需要重复使用的操作,定义为公共的语句块,即可称为函数(给一堆命令取一个别名) 函数可以使脚本中的代码更加简洁,增强易读性,提高脚本的执行效率 #函数定义格式1 ...

  6. jmeter之json提取器详解

    Json提取器详解 *Apply to:参照正则表达式提取器 *Names of created:自定义变量名. 变量名可以填写多个,变量名之间使用分号进行分隔. 一旦变量名有多个,则下方的json ...

  7. Apache Superset1.2.0教程(四)—— CentOS环境安装

    前文中,我们已经在windows环境进行了superset的安装,也对图表功能进行了展示.但是在平时使用以及生产环境中,还是需要在centos环境下进行操作. 本文将带大家详解在centos7环境进行 ...

  8. 我,35岁Android开发,高龄入职鹅厂,试用期未过被劝退......今年实惨

    今天,笔者盘点.综合分享一位腾讯员工的"心声".这份心声中干货还是不少的,主要关于腾讯的一些职场生活--希望这些"干货"能对你有所帮助. 什么部门?给补偿吗? ...

  9. goproxy.io

    goproxy.io 是全球最早的 Go modules 镜像代理服务之一, 采用 CDN 加速服务为开发者提供依赖下载, 该服务由一批热爱开源, 热爱 Go 语言的年轻人开发维护.从 Go 1.11 ...

  10. .Net Core with 微服务 - 分布式事务 - 2PC、3PC

    最近比较忙,好久没更新了.这次我们来聊一聊分布式事务. 在微服务体系下,我们的应用被分割成多个服务,每个服务都配置一个数据库.如果我们的服务划分的不够完美,那么为了完成业务会出现非常多的跨库事务.即使 ...