- 背景:
在一些项目中,会采用集成的关系来定义数据库实体类,比如:人(Person)与学生(Student),学生来源与人,所以人的基本属性学生也拥有;但学生有的一些属性,人就不具有。人与学生之间很显然就拥有了继承关系------学生继承于人,人是父类,学生是子类。
那么,这种继承关系在hibernate是如何映射呢?
对于面向对象的程序设计语言而言,继承和多态是两个最基本的概念。hibernate的集成映射可以理解为持久化类之间的继承关系。在上边的例子中,学生集成了人,可以认为学生是一个特殊的人,如果对人进行查询,学生的实例也将被得到。
在hibernate中支持三种继承映射策略:
1)使用subclass进行映射:将域模型中的每一个实体对象映射到一个独立的表中,也就是说不用在关系数据模型中考虑域模型中的继承关系和多态。
2)使用jioned-subclass进行映射:对于继承关系中的子类使用同一个表,这就需要在数据库表中增加额外的区分子类类型的字段。
3)使用union-subclass进行映射:域模型中的每个类映射到一个表,通过关系数据模型中的外键来描述表之间的继承关系。这也就相当于按照域模型的结构来建立数据库中的表,并通过外键来建立表之间的继承关系。
- 使用subclass进行映射
新建工程Hibernate08,导入hibernate开发包及mysql驱动包。
在src下新建hibernate.cfg.xml配置文件:
1 2 56 7 34root 8123456 9com.mysql.jdbc.Driver 10jdbc:mysql://localhost/hibernate_01 11 12 14org.hibernate.dialect.MySQL5InnoDBDialect 15 16true 17 18true 19 20update 21 22thread 23 24500 2520 2610 272000 282000 2910 30 3132 33
在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 }
新建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 }
添加Person.hbm.xml配置文件:
1 2 4 56 7 278 11 12 139 10 14 15 16 1817 19 21 2220 23 2624 25
注意:
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 @Before21 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 @After32 public void destory() {33 transaction.commit();34 session.close();35 sessionFactory.close();36 }37 }
测试:
在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=InnoDB12 Hibernate: 13 insert 14 into15 PERSONS16 (NAME, AGE, TYPE) 17 values18 (?, ?, 'person')19 Hibernate: 20 insert 21 into22 PERSONS23 (NAME, AGE, CLASS_NAME, SCHOOL_NAME, TYPE) 24 values25 (?, ?, ?, ?, 'student')
数据库查寻结果:
添加测试函数2:
@Test public void testSelect() { Listpersons = session.createQuery("FROM Person").list(); System.out.println(persons.size()); List 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 from10 PERSONS person0_11 212 Hibernate: 13 select14 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 from20 PERSONS student0_ 21 where22 student0_.TYPE='student'23 1
- 使用jioned-subclass进行映射
在工程中复制包com.dx.hibernate06.extend,并命名新包名称为:com.dx.hibernate06.joined.subclass
修改Person.hbm.xml:
1 2 4 56 7 278 11 129 10 13 1514 16 18 1917 20 2621 2322 24 25
注意:
1)这里不需要添加discriminator(辨别列)节点配置,也不需要在table和joined-subclass节点中设置discriminator-value(辨别列值);
2)但需要在joined-subclass节点中指定表名,及在节点内部指定key column。
修改hibernate.cfg.xml,修改mapping节点指定文件路径:
。。。
测试:
在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=InnoDB17 Hibernate: 18 19 alter table STUDENTS 20 add constraint FK3md9kn7axci4c8qrnaav8ybo 21 foreign key (STUDENT_ID) 22 references PERSONS (ID)23 Hibernate: 24 insert 25 into26 PERSONS27 (NAME, AGE) 28 values29 (?, ?)30 Hibernate: 31 insert 32 into33 PERSONS34 (NAME, AGE) 35 values36 (?, ?)37 Hibernate: 38 insert 39 into40 STUDENTS41 (CLASS_NAME, SCHOOL_NAME, STUDENT_ID) 42 values43 (?, ?, ?)
数据库查寻结果:
执行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 from13 PERSONS person0_ 14 left outer join15 STUDENTS person0_1_ 16 on person0_.ID=person0_1_.STUDENT_ID17 218 Hibernate: 19 select20 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 from26 STUDENTS student0_ 27 inner join28 PERSONS student0_1_ 29 on student0_.STUDENT_ID=student0_1_.ID30 1
- 使用union-subclass进行映射
在工程中复制包com.dx.hibernate06.extend,并命名新包名称为:com.dx.hibernate06.union.subclass
修改Person.hbm.xml:
1 2 4 56 7 228 119 10 12 1413 15 1716 18 2119 20
注意:
1)这里只需要指定union-subclass对应的表,及指定其独有的列;
2)Person的ID生成类型不能为identity,不能为native,这里采用的increment。
修改hibernate.cfg.xml,修改mapping节点指定文件路径:
1 2 56 7 。。。 8 109
测试:
在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=InnoDB19 Hibernate: 20 select21 max(ids_.mx) 22 from23 ( select24 max(ID) as mx 25 from26 STUDENTS 27 union28 select29 max(ID) as mx 30 from31 PERSONS 32 ) ids_33 Hibernate: 34 insert 35 into36 PERSONS37 (NAME, AGE, ID) 38 values39 (?, ?, ?)40 Hibernate: 41 insert 42 into43 STUDENTS44 (NAME, AGE, CLASS_NAME, SCHOOL_NAME, ID) 45 values46 (?, ?, ?, ?, ?)
数据库查寻结果:
执行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 from10 ( select11 ID,12 NAME,13 AGE,14 null as CLASS_NAME,15 null as SCHOOL_NAME,16 0 as clazz_ 17 from18 PERSONS 19 union20 select21 ID,22 NAME,23 AGE,24 CLASS_NAME,25 SCHOOL_NAME,26 1 as clazz_ 27 from28 STUDENTS 29 ) person0_30 231 Hibernate: 32 select33 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 from39 STUDENTS student0_40 1