hibernate支持三种基本的继承映射策略:
1、每个类分层结构一张表映射
2、每个子类一张表映射
3、每个具体类一张表映射
我们先来分析第一种策略,假设有一个父类Person,它有两个子类Teacher和Student,都继承了Person类,如图:
我们可以把这种关系的数据,设计到一张表中展示,如图:
下面我们来看下怎样来实现实体类和对应的映射关系来生成这张表。
Person类:
public class Person {
private int id;
private String name;
private int age;
//省略get/set
}
Teacher类:
public class Teacher extends Person{
private int salary;
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
}
Student类:
public class Student extends Person{
private String work;
public String getWork() {
return work;
}
public void setWork(String work) {
this.work = work;
}
}
Person.hbm.xml配置文件
<hibernate-mapping package="com.test.pojo">
<class name="Person">
<id name="id">
<generator class="native"></generator>
</id>
<!-- discriminator指明鉴别器
column:数据库表字段,用来区分不同的子类subclass,具体的数值,来源于不同的subclass中的discriminator-value
-->
<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>
HibernateUtil类
public class HibernateUtil {
private static Configuration cfg=null;
private static SessionFactory factory=null;
private static Session session=null;
static{
cfg=new Configuration().configure();
factory=cfg.buildSessionFactory(new StandardServiceRegistryBuilder()
.applySettings(cfg.getProperties()).build());
}
public static Session getSession(){
if(factory!=null)
return session=factory.openSession();
factory=cfg.buildSessionFactory(new StandardServiceRegistryBuilder()
.applySettings(cfg.getProperties()).build());
return session=factory.openSession();
}
public static void closeSession(){
if(session!=null && session.isOpen())
session.close();
}
}
hibernate.cfg.xml配置文件
<hibernate-configuration>
<session-factory>
<!-- 数据库配置信息 -->
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="connection.url">
jdbc:mysql:///hibernatetest
</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<!-- 数据库方言 -->
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<!-- 映射文件 -->
<mapping resource="com/test/pojo/Person.hbm.xml" />
</session-factory>
</hibernate-configuration>
测试类
public class HibernateTest {
@Test
public void testCreateDB(){
Configuration cfg=new Configuration().configure();
SchemaExport se=new SchemaExport(cfg);
//第一个参数表示是否生成ddl脚本,第二个参数表示是否执行到数据库中
se.create(true, true);
}
/**
* 保存数据
*/
@Test
public void save(){
Session session=null;
Transaction tx=null;
try{
session=HibernateUtil.getSession();
tx=session.beginTransaction();
Teacher teacher=new Teacher();
teacher.setName("teacher");
teacher.setAge(20);
teacher.setSalary(5000);
Student student=new Student();
student.setName("stu1");
student.setAge(20);
student.setWork("hello world");
Student stu=new Student();
stu.setName("stu2");
stu.setAge(21);
stu.setWork("Struts2");
session.save(student);
session.save(stu);
session.save(teacher);
tx.commit();
}catch(Exception e){
if(tx!=null)
tx.rollback();
e.printStackTrace();
}finally{
HibernateUtil.closeSession();
}
}
@Test
public void testGet(){
Session session=null;
Transaction tx=null;
try{
session=HibernateUtil.getSession();
tx=session.beginTransaction();
//取数据。
//查询数据时,如果使用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());
}
tx.commit();
}catch(Exception e){
tx.rollback();
e.printStackTrace();
}finally{
HibernateUtil.closeSession();
}
}
}
结果可自己运行查看。
总结:
1、在单表继承映射中,hibernate通过鉴别器来识别子类的类型。鉴别器由hibernate来进行维护。
2、查询数据时,如果使用get查询得到的数据类型可以进行多态判断;如果使用load查询,load是懒加载(lazy),返回的是代理类,不能进行判断。
3、Person.hbm.xml中子类的配置还有一种形式:就是将subclass放到class同级目录下,但必须指明继承自那个类。如图: