zoukankan      html  css  js  c++  java
  • Hibernate第九篇【组件映射、继承映射】

    前言

    到目前位置,我们已经学习了一对一、一对多、多对一、多对多映射了…既然Hibernate是ORM实现的框架,它还提供了组件映射和继承映射..本博文主要讲解组件映射和继承映射

    Java主要的类主要有两种方式

    • 组合关系,组合关系对应的就是组件映射
    • 继承关系,继承关系对应的就是继承映射

    组件映射

    组件映射实际上就是将组合关系的数据映射成一张表,组件类和被包含的组件类映射成一张表

    有的时候,两个类的关系明显不是继承关系,但两个类的亲密程度很高,在一个类里边需要用到另外一个类…那么就在类中定义一个变量来维护另一个类的关系,这种就叫组合关系!

    需求:汽车和轮子。汽车需要用到轮子,但是轮子的爸爸不可能是汽车吧?

    设计数据库

    这里写图片描述

    设计实体

    Wheel.java

    
    public class Wheel {
    
        private int  count;
        private int size;
    
        public int getCount() {
            return count;
        }
    
        public void setCount(int count) {
            this.count = count;
        }
    
        public int getSize() {
            return size;
        }
    
        public void setSize(int size) {
            this.size = size;
        }
    }
    
    

    Car.java,使用变量维护Wheel

    package zhongfucheng.aa;
    
    /**
     * Created by ozc on 2017/5/7.
     */
    public class Car {
    
        private int id;
        private String name;
        private Wheel wheel;
    
        public Wheel getWheel() {
            return wheel;
        }
    
        public void setWheel(Wheel wheel) {
            this.wheel = wheel;
        }
    
        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;
        }
    }
    

    映射表

    使用了一个新标签<component>,组件映射标签。

    
    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    
    <hibernate-mapping package="zhongfucheng.aa" >
    
        <class name="Car" table="Car" >
    
            <!--映射主键-->
            <id name="id" column="id">
                <generator class="native"></generator>
            </id>
    
            <!--映射普通字段-->
            <property name="name" column="name" ></property>
    
    
            <!--
                映射组件字段
            -->
            <component name="wheel">
                <property name="count"></property>
                <property name="size"></property>
            </component>
    
        </class>
    
    </hibernate-mapping>
    

    测试

    package zhongfucheng.aa;
    
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;
    import org.hibernate.classic.Session;
    
    /**
     * Created by ozc on 2017/5/6.
     */
    public class App5 {
        public static void main(String[] args) {
    
    
            //创建对象
            Wheel wheel = new Wheel();
            Car car = new Car();
    
            //设置属性
            wheel.setCount(43);
            wheel.setSize(22);
            car.setName("宝马");
    
            //维护关系
            car.setWheel(wheel);
            //获取加载配置管理类
            Configuration configuration = new Configuration();
    
    
            configuration.configure().addClass(Car.class);
    
            //创建Session工厂对象
            SessionFactory factory = configuration.buildSessionFactory();
    
            //得到Session对象
            Session session = factory.openSession();
    
            //使用Hibernate操作数据库,都要开启事务,得到事务对象
            Transaction transaction = session.getTransaction();
    
            //开启事务
            transaction.begin();
    
            session.save(car);
    
            //提交事务
            transaction.commit();
    
            //关闭Session
            session.close();
    
    
        }
    }

    这里写图片描述

    传统方式继承

    需求:动物、猫、猴子。猫继承着动物

    传统方式继承的特点就是:有多少个子类就写多少个配置文件.

    表结构

    我们的表应该是这样的:id和name从Animal中继承,catchMouse是子类的具体行为。

    这里写图片描述

    实体

    Animal.java

    
    package zhongfucheng.aa;
    
    // 动物类
    public abstract class Animal {
    
        private int id;
        private String name;
    
    
        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;
        }
    
    }
    

    Cat.java继承着Animail

    
    package zhongfucheng.aa;
    
    public class Cat extends Animal{
    
        // 抓老鼠
        private String catchMouse;
    
        public String getCatchMouse() {
            return catchMouse;
        }
    
        public void setCatchMouse(String catchMouse) {
            this.catchMouse = catchMouse;
        }
    }

    映射文件

    简单继承的映射文件很好写,在属性上,直接写父类的属性就可以了。

    但是也有致命的缺点:如果子类有很多,就需要写很多的配置文件

    
    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    
    <hibernate-mapping package="zhongfucheng.aa" >
    
        <class name="Cat" table="cat" >
    
            <!--映射主键-->
            <id name="id" column="id">
                <generator class="native"></generator>
            </id>
    
            <!--
                映射普通字段
                父类的属性直接引用就行了,比如name属性,直接写就行了!
            -->
            <property name="name" column="name" ></property>
            <property name="catchMouse" column="catchMouse" ></property>
    
    
        </class>
    
    </hibernate-mapping>
    

    测试

    
    package zhongfucheng.aa;
    
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;
    import org.hibernate.classic.Session;
    
    public class App5 {
        public static void main(String[] args) {
    
    
            //创建对象
            Cat cat = new Cat();
    
            //设置属性
    
            cat.setName("大花猫");
            cat.setCatchMouse("捉大老鼠");
    
            //获取加载配置管理类
            Configuration configuration = new Configuration();
    
    
            configuration.configure().addClass(Cat.class);
    
            //创建Session工厂对象
            SessionFactory factory = configuration.buildSessionFactory();
    
            //得到Session对象
            Session session = factory.openSession();
    
            //使用Hibernate操作数据库,都要开启事务,得到事务对象
            Transaction transaction = session.getTransaction();
    
            //开启事务
            transaction.begin();
    
            session.save(cat);
    
            //如果取数据时候Animal父类接收的话,需要给出Anmail的全名
    
    
            //提交事务
            transaction.commit();
    
            //关闭Session
            session.close();
    
    
        }
    }

    这里写图片描述


    把所有子类映射成一张表

    前面我们采用的是:每个子类都需要写成一个配置文件,映射成一张表

    如果子类的结构很简单,只比父类多几个属性。就像上面的例子…我们可以将所有的子类都映射成一张表中

    但是呢,这样是不符合数据库设计规范的…..因为表中的数据可能是猫,可能是猴子…这明显是不合适的…

    由于表中可能存在猫,存在猴子,为了区分是什么类型的。我们需要使用鉴别器

    我们了解一下…

    数据表

    这里写图片描述

    实体

    实体和上面雷同,只多了一个猴子的实体表

    Monkey.java

    
    public class Monkey extends Animal {
    
        // 吃香蕉
        private String eatBanana;
    
        public String getEatBanana() {
            return eatBanana;
        }
    
        public void setEatBanana(String eatBanana) {
            this.eatBanana = eatBanana;
        }
    
    }
    
    

    映射文件

    使用了subClass这个节点和鉴别器

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    
    <!-- 
        继承映射, 所有的子类都映射到一张表
     -->
    <hibernate-mapping package="cn.itcast.e_extends2">
    
        <class name="Animal" table="t_animal">
            <id name="id">
                <generator class="native"></generator>
            </id>
            <!-- 指定鉴别器字段(区分不同的子类) -->
            <discriminator column="type_"></discriminator>
    
            <property name="name"></property>
    
            <!-- 
                子类:猫
                    每个子类都用subclass节点映射
                    注意:一定要指定鉴别器字段,否则报错!
                    鉴别器字段:作用是在数据库中区别每一个子类的信息, 就是一个列
                discriminator-value="cat_"
                    指定鉴别器字段,即type_字段的值
                    如果不指定,默认为当前子类的全名
             -->
             <subclass name="Cat" discriminator-value="cat_">
                <property name="catchMouse"></property>
             </subclass>
    
             <!-- 
                子类:猴子
              -->
              <subclass name="Monkey" discriminator-value="monkey_">
                <property name="eatBanana"></property>
              </subclass>
    
        </class>
    
    
    </hibernate-mapping>
    

    测试

    加载的是Animal父类的映射文件。保存的是cat和monkey。

    
    package zhongfucheng.aa;
    
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;
    import org.hibernate.classic.Session;
    
    public class App5 {
        public static void main(String[] args) {
    
    
            //创建对象
            Cat cat = new Cat();
            Monkey monkey = new Monkey();
    
            //设置属性
            cat.setName("大花猫");
            cat.setCatchMouse("小老鼠");
            monkey.setEatBanana("吃香蕉");
            monkey.setName("大猴子");
    
            //获取加载配置管理类
            Configuration configuration = new Configuration();
    
            //加载Animal的映射文件!
            configuration.configure().addClass(Animal.class);
    
            //创建Session工厂对象
            SessionFactory factory = configuration.buildSessionFactory();
    
            //得到Session对象
            Session session = factory.openSession();
    
            //使用Hibernate操作数据库,都要开启事务,得到事务对象
            Transaction transaction = session.getTransaction();
    
            //开启事务
            transaction.begin();
    
            session.save(cat);
            session.save(monkey);
    
            //提交事务
            transaction.commit();
    
            //关闭Session
            session.close();
    
    
        }
    }

    这里写图片描述


    每个类映射一张表(3张表)

    父类和子类都各对应一张表。那么就有三张表了

    这种结构看起来是完全面向对象,但是表之间的结构会很复杂,插入一条子类的信息,需要两条SQL

    数据表设计

    这里写图片描述

    映射文件

    使用到了<joined-subclass >这个节点

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    
    
    <hibernate-mapping package="zhongfucheng.aa">
    
        <class name="Animal" table="t_animal">
            <id name="id">
                <generator class="native"></generator>
            </id>
    
            <property name="name"></property>
    
    
            <!--
                Animal下的子类映射成一张表
                    指定子类的类型,对应的表
                    指定子类的外键字段【需要对应Animal】
                    指定子类的普通属性
            -->
            <joined-subclass name="Cat" table="cat_">
                <!--key对应的是外键字段-->
                <key column="animal_id"></key>
                <property name="catchMouse"></property>
            </joined-subclass>
    
            <joined-subclass name="Monkey" table="monkey_">
                <!--key对应的是外键字段-->
                <key column="animal_id"></key>
                <property name="eatBanana"></property>
            </joined-subclass>
    
    
        </class>
    
    
    </hibernate-mapping>
    
    
    

    测试

    package zhongfucheng.aa;
    
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;
    import org.hibernate.classic.Session;
    
    public class App5 {
        public static void main(String[] args) {
    
    
            //创建对象
            Cat cat = new Cat();
            Monkey monkey = new Monkey();
    
            //设置属性
            cat.setName("大花猫");
            cat.setCatchMouse("小老鼠");
            monkey.setEatBanana("吃香蕉");
            monkey.setName("大猴子");
    
            //获取加载配置管理类
            Configuration configuration = new Configuration();
    
            //加载类对应的映射文件!
            configuration.configure().addClass(Animal.class);
    
            //创建Session工厂对象
            SessionFactory factory = configuration.buildSessionFactory();
    
            //得到Session对象
            Session session = factory.openSession();
    
            //使用Hibernate操作数据库,都要开启事务,得到事务对象
            Transaction transaction = session.getTransaction();
    
            //开启事务
            transaction.begin();
    
            session.save(cat);
            session.save(monkey);
    
            //提交事务
            transaction.commit();
    
            //关闭Session
            session.close();
    
    
        }
    }

    每保存一个子类对象需要两条SQL语句!

    这里写图片描述


    (推荐)每个子类映射一张表, 父类不对应表(2张表)

    • 使用过了一张表保存所有子类的数据,这不符合数据库设计规范
    • 每个子类、父类都拥有一张表..表结构太过于繁琐..添加信息时,过多的SQL

    我们即将使用的是:每个子类映射成一张表,父类不对应表…这和我们传统方式继承是一样的。只不过在hbm.xml文件中使用了<union-subclass>这个节点,由于有了这个节点,我们就不需要每个子类都写一个配置文件了。

    数据库表设计

    这里写图片描述

    映射文件

    • 想要父类不映射成数据库表,只要在class中配置为abstract即可
    • 使用了union-subclass节点,主键就不能采用自动增长策略了。我们改成UUID即可。当然啦,对应的实体id类型要改成String
    
    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    
    
    <hibernate-mapping package="zhongfucheng.aa">
    
    
        <!--
            想要父类不映射成表,设置成abstract
        -->
        <class name="Animal" abstract="true">
    
            <!--
                如果使用了union-subclass节点,那么主键生成策略不能是自增长,我们改成uuid即可
            -->
            <id name="id">
                <generator class="uuid"></generator>
            </id>
    
            <property name="name"></property>
    
    
            <!--
                将子类的信息都映射成一张表
                    给出属性的名称
                    属性对应的数据库表
                    普通字段
            -->
            <union-subclass name="Cat" table="cat_">
                <property name="catchMouse"></property>
            </union-subclass>
    
            <union-subclass name="Monkey" table="monkey_">
                <property name="eatBanana"></property>
            </union-subclass>
    
    
        </class>
    
    
    </hibernate-mapping>
    

    测试

    
    package zhongfucheng.aa;
    
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;
    import org.hibernate.classic.Session;
    
    public class App5 {
        public static void main(String[] args) {
    
    
            //创建对象
            Cat cat = new Cat();
            Monkey monkey = new Monkey();
    
            //设置属性
            cat.setName("大花猫");
            cat.setCatchMouse("小老鼠");
            monkey.setEatBanana("吃香蕉");
            monkey.setName("大猴子");
    
            //获取加载配置管理类
            Configuration configuration = new Configuration();
    
            //加载类对应的映射文件!
            configuration.configure().addClass(Animal.class);
    
            //创建Session工厂对象
            SessionFactory factory = configuration.buildSessionFactory();
    
            //得到Session对象
            Session session = factory.openSession();
    
            //使用Hibernate操作数据库,都要开启事务,得到事务对象
            Transaction transaction = session.getTransaction();
    
            //开启事务
            transaction.begin();
    
            session.save(cat);
            session.save(monkey);
    
            //提交事务
            transaction.commit();
    
            //关闭Session
            session.close();
    
    
        }
    }

    这里写图片描述

    总结

    由于我们的传统继承映射每个子类都对应一个配置文件,这样十分麻烦。因此.hbm.xml就给出了几个节点供我们使用,分别有以下的情况:

    • 子类父类共有一张表subclass
      • 不符合数据库设计规范
      • 需要使用鉴别器
    • 子类、父类都有自己的表joined-subclass,那么就是三张表
      • 表的结构太过繁琐
      • 插入数据时要生成SQL至少就要两条
    • 子类拥有自己的表、父类不对应表【推荐】union-subclass
      • 父类不对应表要使用abstract来修饰
      • 主键的id不能使用自增长策略,修改成UUID就好了。对应的JavaBean的id设置成String就好

  • 相关阅读:
    入门经典 第七章 7.3.3 二进制生成子集
    gdb调试方法简要总结
    Erlang_1
    hdu 1144
    创建一个类,重载运算符实现多项式的加,减,乘运算
    ubuntu12.04 iNodeClient 连校园网
    ftime使用
    CodeForce 264 A. Escape from Stones
    hdu 1161 Eddy's mistakes
    hdu 1064
  • 原文地址:https://www.cnblogs.com/zhong-fucheng/p/7202961.html
Copyright © 2011-2022 走看看