继承映射有三种方式
- 基于一张表的继承映射
- 基于每个具体类一张表的继承映射
- 基于每个类一张表的继承映射
我们考虑下面的继承关系
学生和老师都继承Person,区别就是老师有工资,学生有作业。那么考虑怎么配置让数据库知道这种关系。
三个类代码分别是(get/set方法都省略了)
public class Person {
private int id;
private String name;
private int age;
}
public class Student extends Person{
private String work;
}
public class Teacher extends Person{
private int salary;·
}
下面针对三种方法一一详细讲解,只需要配置超类的 即Person.hbm.xml即可
1. 基于一张表的继承映射(推荐使用)
主要通过鉴别器 discriminator
一张表这么存
<hibernate-mapping package="cn.siggy.pojo">
<class name="Person">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<!-- 指明鉴别器 -->
<discriminator column="type" type="string"/>
<property name="name"/>
<property name="age"/>
<subclass name="Student" discriminator-value="s">
<property name="work"/>
</subclass>
<subclass name="Teacher" discriminator-value="t">
<property name="salary"/>
</subclass>
</class>
</hibernate-mapping>
测试
session = factory.openSession();
tx = session.beginTransaction();
Teacher teacher = new Teacher();
teacher.setName("siggy");
teacher.setAge(26);
teacher.setSalary(5000);
Student student = new Student();
student.setName("小明");
student.setAge(22);
student.setWork("hello world");
Student student1 = new Student();
student1.setName("小强");
student1.setAge(20);
student1.setWork("struts2");
session.save(student);
session.save(student1);
session.save(teacher);
tx.commit();
查询数据时,如果使用get查询得到的数据类型可以进行多态判断。如果是通过load(lazy)查询,不能判断。如下:
Person person = (Person)session.get(Person.class, 2);
System.out.println(person.getName());
if(person instanceof Student){
Student stu = (Student)person;
System.out.println(stu.getWork());
}
2. 基于每个具体类一张表的继承映射
<hibernate-mapping package="cn.siggy.pojo">
<class name="Person" abstract="true">
<!-- Person表没有任何数据,所以我们可以指定不生成这张表,就是abstract为true -->
<id name="id">
<!-- 主键的生成不能使用identity.建议使用uuid,sequence,assigned等。所以我们要setID -->
<generator class="assigned"></generator>
</id>
<property name="name" />
<property name="age" />
<union-subclass name="Student">
<property name="work" />
</union-subclass>
<union-subclass name="Teacher">
<property name="salary" />
</union-subclass>
</class>
</hibernate-mapping>
identity:由底层数据库生成标识符。identity是由数据库自己生成的,但这个主键必须设置为自增长,前提条件是低层数据库支持自动增长字段类型 。因为我们是Person主键的id是Student和Teacher共享的,所以不能是identity。我们可以用assigned,所以我们存数据的时候需要指定ID。
“assigned” 主键由外部程序负责生成,在 save() 之前指定一个。
测试 存数据的时候需要指定ID,且student和teacher的id相互之间和自己都不能重复
session = factory.openSession();
tx = session.beginTransaction();
Teacher teacher = new Teacher();
teacher.setId(1);
teacher.setName("siggy");
teacher.setAge(26);
teacher.setSalary(5000);
Student student = new Student();
student.setId(2);
student.setName("小明");
student.setAge(22);
student.setWork("hello world");
Student student1 = new Student();
student1.setId(3);
student1.setName("小强");
student1.setAge(20);
student1.setWork("struts2");
session.save(student);
session.save(student1);
session.save(teacher);
tx.commit();
这种方式数据表的结构更加合理但是多态查询效率不高,会联合查询
3. 基于每个类一张表的继承映射
<hibernate-mapping package="cn.siggy.pojo">
<class name="Person">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<property name="name"/>
<property name="age"/>
<joined-subclass name="Teacher">
<key column="id"/>
<property name="salary"/>
</joined-subclass>
<joined-subclass name="Student">
<key column="id"/>
<property name="work"/>
</joined-subclass>
</class>
</hibernate-mapping>
测试
session = factory.openSession();
tx = session.beginTransaction();
Teacher teacher = new Teacher();
teacher.setName("siggy");
teacher.setAge(26);
teacher.setSalary(5000);
Student student = new Student();
student.setName("小明");
student.setAge(22);
student.setWork("hello world");
Student student1 = new Student();
student1.setName("小强");
student1.setAge(20);
student1.setWork("struts2");
session.save(student);
session.save(student1);
session.save(teacher);
tx.commit();
3种继承映射比较:
所有存1张表,数据冗余比较多。效率比较高。推荐使用。
每个子类一张表。数据冗余比较少,查询效率低,主键不能自增。需要指明为assigned,uuid,hilo等
每个类一张表。数据冗余比较少。查询效率比每个子类一张表稍高。维护的表的个数多。