• Hibernate(十一):映射继承关系的三种方案


    • 背景:

      在一些项目中,会采用集成的关系来定义数据库实体类,比如:人(Person)与学生(Student),学生来源与人,所以人的基本属性学生也拥有;但学生有的一些属性,人就不具有。人与学生之间很显然就拥有了继承关系------学生继承于人,人是父类,学生是子类。

      那么,这种继承关系在hibernate是如何映射呢?

      对于面向对象的程序设计语言而言,继承和多态是两个最基本的概念。hibernate的集成映射可以理解为持久化类之间的继承关系。在上边的例子中,学生集成了人,可以认为学生是一个特殊的人,如果对人进行查询,学生的实例也将被得到。

      在hibernate中支持三种继承映射策略:

      1)使用subclass进行映射:将域模型中的每一个实体对象映射到一个独立的表中,也就是说不用在关系数据模型中考虑域模型中的继承关系和多态。

      2)使用jioned-subclass进行映射:对于继承关系中的子类使用同一个表,这就需要在数据库表中增加额外的区分子类类型的字段。

      3)使用union-subclass进行映射:域模型中的每个类映射到一个表,通过关系数据模型中的外键来描述表之间的继承关系。这也就相当于按照域模型的结构来建立数据库中的表,并通过外键来建立表之间的继承关系。

    • 使用subclass进行映射

    新建工程Hibernate08,导入hibernate开发包及mysql驱动包。

    在src下新建hibernate.cfg.xml配置文件:

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!DOCTYPE hibernate-configuration PUBLIC
     3         "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
     4         "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
     5 <hibernate-configuration>
     6     <session-factory>
     7         <property name="hibernate.connection.username">root</property>
     8         <property name="hibernate.connection.password">123456</property>
     9         <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    10         <property name="hibernate.connection.url">jdbc:mysql://localhost/hibernate_01</property>
    11 
    12         <!-- <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> 
    13             <property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property> -->
    14         <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
    15 
    16         <property name="hibernate.show_sql">true</property>
    17 
    18         <property name="hibernate.format_sql">true</property>
    19 
    20         <property name="hibernate.hbm2ddl.auto">update</property>
    21 
    22         <property name="hibernate.current_session_context_class">thread</property>
    23 
    24         <property name="hibernate.c3p0.max_size">500</property>
    25         <property name="hibernate.c3p0.min_size">20</property>
    26         <property name="hibernate.c3p0.max_statements">10</property>
    27         <property name="hibernate.c3p0.timeout">2000</property>
    28         <property name="hibernate.c3p0.idle_test_period">2000</property>
    29         <property name="hibernate.c3p0.acquire_increment">10</property>
    30 
    31         <mapping resource="com/dx/hibernate06/extend/Person.hbm.xml" />
    32             
    33     </session-factory>
    34 </hibernate-configuration>
    View Code

    在src下新建com.dx.hibernate06.extend包,在该包下新建Person.java:

     1 package com.dx.hibernate06.extend;
     2 
     3 public class Person {
     4     private Integer id;
     5     private String name;
     6     private Integer age;
     7 
     8     public Person() {
     9 
    10     }
    11 
    12     public Integer getId() {
    13         return id;
    14     }
    15 
    16     public void setId(Integer id) {
    17         this.id = id;
    18     }
    19 
    20     public String getName() {
    21         return name;
    22     }
    23 
    24     public void setName(String name) {
    25         this.name = name;
    26     }
    27 
    28     public Integer getAge() {
    29         return age;
    30     }
    31 
    32     public void setAge(Integer age) {
    33         this.age = age;
    34     }
    35 }
    View Code

    新建Student.java(继承自Person):

     1 package com.dx.hibernate06.extend;
     2 
     3 public class Student extends Person {
     4     private String className;
     5     private String schoolName;
     6 
     7     public Student() {
     8 
     9     }
    10 
    11     public String getClassName() {
    12         return className;
    13     }
    14 
    15     public void setClassName(String className) {
    16         this.className = className;
    17     }
    18 
    19     public String getSchoolName() {
    20         return schoolName;
    21     }
    22 
    23     public void setSchoolName(String schoolName) {
    24         this.schoolName = schoolName;
    25     }
    26 
    27 }
    View Code

    添加Person.hbm.xml配置文件:

     1 <?xml version="1.0"?>
     2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
     3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
     4 <!-- Generated 2017-6-8 15:16:00 by Hibernate Tools 3.5.0.Final -->
     5 <hibernate-mapping package="com.dx.hibernate06.extend">
     6     <class name="Person" table="PERSONS" discriminator-value="person">
     7         <id name="id" type="java.lang.Integer">
     8             <column name="ID" />
     9             <generator class="native" />
    10         </id>
    11         
    12         <!-- 配置辨别者列 -->
    13         <discriminator column="TYPE" type="string"></discriminator>
    14         
    15         <property name="name" type="java.lang.String">
    16             <column name="NAME" />
    17         </property>
    18         <property name="age" type="java.lang.Integer">
    19             <column name="AGE" />
    20         </property>
    21 
    22         <subclass name="Student" discriminator-value="student">
    23             <property name="className" column="CLASS_NAME" type="string"></property>
    24             <property name="schoolName" column="SCHOOL_NAME" type="string"></property>
    25         </subclass>
    26     </class>
    27 </hibernate-mapping>

    注意:

    1)在这里并没有定义student.hbm.xml配置文件,而是只需要在Person.hbm.xml配置文件中设置subclass配置项就可以;

    2)除了设置subclass节点,还需要添加discriminator(辨别列)节点配置,且需要在table和subclass节点中设置discriminator-value(辨别列值)。

    添加测试类TestMain.java:

     1 package com.dx.hibernate06.extend;
     2 
     3 import org.hibernate.Session;
     4 import org.hibernate.SessionFactory;
     5 import org.hibernate.Transaction;
     6 import org.hibernate.boot.Metadata;
     7 import org.hibernate.boot.MetadataSources;
     8 import org.hibernate.boot.model.naming.ImplicitNamingStrategyComponentPathImpl;
     9 import org.hibernate.boot.registry.StandardServiceRegistry;
    10 import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
    11 import org.junit.After;
    12 import org.junit.Before;
    13 import org.junit.Test;
    14 
    15 public class TestMain {
    16     private SessionFactory sessionFactory = null;
    17     private Session session = null;
    18     private Transaction transaction = null;
    19 
    20     @Before
    21     public void init() {
    22         StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder().configure().build();
    23         Metadata metadata = new MetadataSources(standardRegistry).getMetadataBuilder().applyImplicitNamingStrategy(ImplicitNamingStrategyComponentPathImpl.INSTANCE).build();
    24 
    25         sessionFactory = metadata.getSessionFactoryBuilder().build();
    26         session = sessionFactory.getCurrentSession();
    27         transaction = session.beginTransaction();
    28     }
    29 
    30 
    31     @After
    32     public void destory() {
    33         transaction.commit();
    34         session.close();
    35         sessionFactory.close();
    36     }
    37 }
    View Code

    测试:

    在TestMain.java中添加测试函数1:

     1     @Test
     2     public void testInsert() {
     3         Person person = new Person();
     4         person.setName("person1");
     5         person.setAge(27);
     6 
     7         Student student = new Student();
     8         student.setName("student1");
     9         student.setAge(22);
    10         student.setClassName("class-1");
    11         student.setSchoolName("浙江大学");
    12 
    13         session.save(person);
    14         session.save(student);
    15     }

    测试执行sql:

     1 Hibernate: 
     2     
     3     create table PERSONS (
     4        ID integer not null auto_increment,
     5         TYPE varchar(255) not null,
     6         NAME varchar(255),
     7         AGE integer,
     8         CLASS_NAME varchar(255),
     9         SCHOOL_NAME varchar(255),
    10         primary key (ID)
    11     ) engine=InnoDB
    12 Hibernate: 
    13     insert 
    14     into
    15         PERSONS
    16         (NAME, AGE, TYPE) 
    17     values
    18         (?, ?, 'person')
    19 Hibernate: 
    20     insert 
    21     into
    22         PERSONS
    23         (NAME, AGE, CLASS_NAME, SCHOOL_NAME, TYPE) 
    24     values
    25         (?, ?, ?, ?, 'student')
    View Code

    数据库查寻结果:

    添加测试函数2:

        @Test
        public void testSelect() {
            List<Person> persons = session.createQuery("FROM Person").list();
            System.out.println(persons.size());
    
            List<Student> students = session.createQuery("FROM Student").list();
            System.out.println(students.size());
        }

    执行sql及结果:

     1 Hibernate: 
     2     select
     3         person0_.ID as ID1_0_,
     4         person0_.NAME as NAME3_0_,
     5         person0_.AGE as AGE4_0_,
     6         person0_.CLASS_NAME as CLASS_NA5_0_,
     7         person0_.SCHOOL_NAME as SCHOOL_N6_0_,
     8         person0_.TYPE as TYPE2_0_ 
     9     from
    10         PERSONS person0_
    11 2
    12 Hibernate: 
    13     select
    14         student0_.ID as ID1_0_,
    15         student0_.NAME as NAME3_0_,
    16         student0_.AGE as AGE4_0_,
    17         student0_.CLASS_NAME as CLASS_NA5_0_,
    18         student0_.SCHOOL_NAME as SCHOOL_N6_0_ 
    19     from
    20         PERSONS student0_ 
    21     where
    22         student0_.TYPE='student'
    23 1
    • 使用jioned-subclass进行映射

    在工程中复制包com.dx.hibernate06.extend,并命名新包名称为:com.dx.hibernate06.joined.subclass

    修改Person.hbm.xml:

     1 <?xml version="1.0"?>
     2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
     3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
     4 <!-- Generated 2017-6-8 15:16:00 by Hibernate Tools 3.5.0.Final -->
     5 <hibernate-mapping package="com.dx.hibernate06.joined.subclass">
     6     <class name="Person" table="PERSONS">
     7         <id name="id" type="java.lang.Integer">
     8             <column name="ID" />
     9             <generator class="native" />
    10         </id>
    11 
    12         <property name="name" type="java.lang.String">
    13             <column name="NAME" />
    14         </property>
    15         <property name="age" type="java.lang.Integer">
    16             <column name="AGE" />
    17         </property>
    18 
    19         <joined-subclass name="Student" table="STUDENTS">
    20             <key>
    21                 <column name="STUDENT_ID"></column>
    22             </key>
    23             <property name="className" column="CLASS_NAME" type="string"></property>
    24             <property name="schoolName" column="SCHOOL_NAME" type="string"></property>
    25         </joined-subclass>
    26     </class>
    27 </hibernate-mapping>

    注意:

    1)这里不需要添加discriminator(辨别列)节点配置,也不需要在table和joined-subclass节点中设置discriminator-value(辨别列值);

    2)但需要在joined-subclass节点中指定表名,及在节点内部指定key column。

     修改hibernate.cfg.xml,修改mapping节点指定文件路径:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE hibernate-configuration PUBLIC
            "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
    <hibernate-configuration>
        <session-factory>
            。。。
            <mapping resource="com/dx/hibernate06/joined/subclass/Person.hbm.xml" />            
        </session-factory>
    </hibernate-configuration>

    测试:

    在com.dx.hibernate06.joined.subclass.TestMain.java中执行测试函数testInsert()(备注:该测试函数与上边测试函数一致),执行sql及结果:

     1 Hibernate: 
     2     
     3     create table PERSONS (
     4        ID integer not null auto_increment,
     5         NAME varchar(255),
     6         AGE integer,
     7         primary key (ID)
     8     ) engine=InnoDB
     9 Hibernate: 
    10     
    11     create table STUDENTS (
    12        STUDENT_ID integer not null,
    13         CLASS_NAME varchar(255),
    14         SCHOOL_NAME varchar(255),
    15         primary key (STUDENT_ID)
    16     ) engine=InnoDB
    17 Hibernate: 
    18     
    19     alter table STUDENTS 
    20        add constraint FK3md9kn7axci4c8qrnaav8ybo 
    21        foreign key (STUDENT_ID) 
    22        references PERSONS (ID)
    23 Hibernate: 
    24     insert 
    25     into
    26         PERSONS
    27         (NAME, AGE) 
    28     values
    29         (?, ?)
    30 Hibernate: 
    31     insert 
    32     into
    33         PERSONS
    34         (NAME, AGE) 
    35     values
    36         (?, ?)
    37 Hibernate: 
    38     insert 
    39     into
    40         STUDENTS
    41         (CLASS_NAME, SCHOOL_NAME, STUDENT_ID) 
    42     values
    43         (?, ?, ?)
    View Code

    数据库查寻结果:

    执行testSelect()测试函数,执行结果及sql:

     1 Hibernate: 
     2     select
     3         person0_.ID as ID1_0_,
     4         person0_.NAME as NAME2_0_,
     5         person0_.AGE as AGE3_0_,
     6         person0_1_.CLASS_NAME as CLASS_NA2_1_,
     7         person0_1_.SCHOOL_NAME as SCHOOL_N3_1_,
     8         case 
     9             when person0_1_.STUDENT_ID is not null then 1 
    10             when person0_.ID is not null then 0 
    11         end as clazz_ 
    12     from
    13         PERSONS person0_ 
    14     left outer join
    15         STUDENTS person0_1_ 
    16             on person0_.ID=person0_1_.STUDENT_ID
    17 2
    18 Hibernate: 
    19     select
    20         student0_.STUDENT_ID as ID1_0_,
    21         student0_1_.NAME as NAME2_0_,
    22         student0_1_.AGE as AGE3_0_,
    23         student0_.CLASS_NAME as CLASS_NA2_1_,
    24         student0_.SCHOOL_NAME as SCHOOL_N3_1_ 
    25     from
    26         STUDENTS student0_ 
    27     inner join
    28         PERSONS student0_1_ 
    29             on student0_.STUDENT_ID=student0_1_.ID
    30 1
    • 使用union-subclass进行映射

    在工程中复制包com.dx.hibernate06.extend,并命名新包名称为:com.dx.hibernate06.union.subclass

    修改Person.hbm.xml:

     1 <?xml version="1.0"?>
     2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
     3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
     4 <!-- Generated 2017-6-8 15:16:00 by Hibernate Tools 3.5.0.Final -->
     5 <hibernate-mapping package="com.dx.hibernate06.union.subclass">
     6     <class name="Person" table="PERSONS">
     7         <id name="id" type="java.lang.Integer">
     8             <column name="ID" />
     9             <generator class="increment" />
    10         </id>
    11         <property name="name" type="java.lang.String">
    12             <column name="NAME" />
    13         </property>
    14         <property name="age" type="java.lang.Integer">
    15             <column name="AGE" />
    16         </property>
    17         <union-subclass name="Student" table="STUDENTS">
    18             <property name="className" column="CLASS_NAME" type="string"></property>
    19             <property name="schoolName" column="SCHOOL_NAME" type="string"></property>
    20         </union-subclass>
    21     </class>
    22 </hibernate-mapping>

    注意:

    1)这里只需要指定union-subclass对应的表,及指定其独有的列;

    2)Person的ID生成类型不能为identity,不能为native,这里采用的increment。

    修改hibernate.cfg.xml,修改mapping节点指定文件路径:

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!DOCTYPE hibernate-configuration PUBLIC
     3         "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
     4         "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
     5 <hibernate-configuration>
     6     <session-factory>
     7         。。。
     8         <mapping resource="com/dx/hibernate06/union/subclass/Person.hbm.xml" />            
     9     </session-factory>
    10 </hibernate-configuration>

    测试:

    在com.dx.hibernate06.union.subclass.TestMain.java中执行测试函数testInsert()(备注:该测试函数与上边测试函数一致),执行sql及结果:

     1 Hibernate: 
     2     
     3     create table PERSONS (
     4        ID integer not null,
     5         NAME varchar(255),
     6         AGE integer,
     7         primary key (ID)
     8     ) engine=InnoDB
     9 Hibernate: 
    10     
    11     create table STUDENTS (
    12        ID integer not null,
    13         NAME varchar(255),
    14         AGE integer,
    15         CLASS_NAME varchar(255),
    16         SCHOOL_NAME varchar(255),
    17         primary key (ID)
    18     ) engine=InnoDB
    19 Hibernate: 
    20     select
    21         max(ids_.mx) 
    22     from
    23         ( select
    24             max(ID) as mx 
    25         from
    26             STUDENTS 
    27         union
    28         select
    29             max(ID) as mx 
    30         from
    31             PERSONS 
    32     ) ids_
    33 Hibernate: 
    34     insert 
    35     into
    36         PERSONS
    37         (NAME, AGE, ID) 
    38     values
    39         (?, ?, ?)
    40 Hibernate: 
    41     insert 
    42     into
    43         STUDENTS
    44         (NAME, AGE, CLASS_NAME, SCHOOL_NAME, ID) 
    45     values
    46         (?, ?, ?, ?, ?)
    View Code

    数据库查寻结果:

    执行testSelect()测试函数,执行结果及sql:

     1 Hibernate: 
     2     select
     3         person0_.ID as ID1_0_,
     4         person0_.NAME as NAME2_0_,
     5         person0_.AGE as AGE3_0_,
     6         person0_.CLASS_NAME as CLASS_NA1_1_,
     7         person0_.SCHOOL_NAME as SCHOOL_N2_1_,
     8         person0_.clazz_ as clazz_ 
     9     from
    10         ( select
    11             ID,
    12             NAME,
    13             AGE,
    14             null as CLASS_NAME,
    15             null as SCHOOL_NAME,
    16             0 as clazz_ 
    17         from
    18             PERSONS 
    19         union
    20         select
    21             ID,
    22             NAME,
    23             AGE,
    24             CLASS_NAME,
    25             SCHOOL_NAME,
    26             1 as clazz_ 
    27         from
    28             STUDENTS 
    29     ) person0_
    30 2
    31 Hibernate: 
    32     select
    33         student0_.ID as ID1_0_,
    34         student0_.NAME as NAME2_0_,
    35         student0_.AGE as AGE3_0_,
    36         student0_.CLASS_NAME as CLASS_NA1_1_,
    37         student0_.SCHOOL_NAME as SCHOOL_N2_1_ 
    38     from
    39         STUDENTS student0_
    40 1
  • 相关阅读:
    oracle length and lengthb
    Oracle对列的操作总结
    配置Spring管理的bean的作用域
    Spring的三种实例化Bean的方式
    编码剖析Spring管理Bean的原理
    SpringMVC学习(十二)——SpringMVC中的拦截器
    SpringMVC学习(十一)——SpringMVC实现Resultful服务
    SpringMVC学习(十)——SpringMVC与前台的json数据交互
    SpringMVC学习(九)——SpringMVC中实现文件上传
    SpringMVC学习(八)——SpringMVC中的异常处理器
  • 原文地址:https://www.cnblogs.com/yy3b2007com/p/6962852.html
Copyright © 2020-2023  润新知