对于类与类之间的继承关系,hibernate提供了三种映射策略。
InheritanceType.SINGE_TABLE:整个层次对应一张表,默认
InheritanceType.JOINED:连接子类的映射策略
InheritanceType.TABLE_PER_CLASS:每个具体类对应一个表。1 整个类层次对应一个表
整个类层次对应一个表的映射策略是Hibernate的默认的继承映射策略,在这种策略下,父类、子类同在一个表中。
为了区分记录到底属于哪个实体,在创建表时,会增加额外一列——辨别者列(discriminator)
在Hibernate中使用整个类层次对应一个表时,使用@DiscriminatorColumn修饰正课继承树的根父类
@Entity
// 定义辨别者列的列名为person_type,列类型为字符串
@DiscriminatorColumn(name="person_type" ,
discriminatorType=DiscriminatorType.STRING)
// 指定Person实体对应的记录在辨别者列的值为"普通人"
@DiscriminatorValue("普通人")
@Table(name="person_inf")
public class Person
{
// 标识属性
@Id @Column(name="person_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
private String name;
}
上面的Person类是整个类继承系统的跟雷,因此程序使用@DiscriminatorColumn修饰该持久化类,也使用了@DiscrimininatorValue修饰它。指定了value="普通人“,这意味着当辨别这列的值为普通人时,Hibernate即可识别该条记录为Person实体。
@Entity
// 指定Employee实体对应的记录在辨别者列的值为"员工"
@DiscriminatorValue("员工")
@Table(name="employee_inf")
public class Employee extends Person
{
// 定义该员工职位的成员变量
private String title;
// 定义该员工工资的成员变量
private double salary;
// 定义和该员工保持关联的Customer关联实体
@OneToMany(cascade=CascadeType.ALL
, mappedBy="employee" , targetEntity=Customer.class)
private Set<Customer> customers
= new HashSet<>();
// 定义和该员工保持关联的Manager关联实体
@ManyToOne(cascade=CascadeType.ALL
,targetEntity=Manager.class)
@JoinColumn(name="manager_id", nullable=true)
private Manager manager;
}
使用这种策略有一个好处就是无论如何查询,记录都保存在一张表内,无需进行union查询。
2 连接子类的映射策略
这种策略不是默认策略,如果需要使用,必须在继承树的根目录中@Inheritance指定映射策略。
采用这种映射策略时,父类实体保存在父类表中,而自恋实体则由父类表和子类表共同存储。在子类表中仅保存子类增加的属性。
@Entity
// 指定使用连接子类的映射策略
@Inheritance(strategy=InheritanceType.JOINED)
@Table(name="person_inf")
public class Person
{
// 标识属性
@Id @Column(name="person_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
private String name;
private char gender;
在这种映射策略下,子类不需要用任何注解修饰
// 员工类继承了Person类
@Entity
@Table(name="employee_inf")
public class Employee extends Person
{
// 定义该员工职位的成员变量
private String title;
// 定义该员工工资的成员变量
private double salary;
// 定义和该员工保持关联的Customer关联实体
@OneToMany(cascade=CascadeType.ALL
, mappedBy="employee" , targetEntity=Customer.class)
private Set<Customer> customers
= new HashSet<>();
// 定义和该员工保持关联的Manager关联实体
@ManyToOne(cascade=CascadeType.ALL
,targetEntity=Manager.class)
@JoinColumn(name="manager_id", nullable=true)
使用这种策略时,查询时可能需要跨越多个表,这取决于继承树的深度,如果深度较深,可能导致性能低下。
3 每个具体类对应一个表的映射策略
这种策略父类的实例保存在父表中,子类的实例保存在子表中。在这种情况下,从数据库来看,很难看出存在继承关系,只是多个实体之间的主键值具有某种连续性,因此不能让数据库为各自的表生成主键值
@Entity
// 指定使用每个具体类对应一张表的映射策略
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
@Table(name="person_inf")
public class Person
{
// 标识属性
@Id @Column(name="person_id")
// 由于不能使用identity主键生成策略,故此处采用hilo主键生成策略
@GenericGenerator(name="person_hilo" , strategy="hilo")
@GeneratedValue(generator="person_hilo")
private Integer id;
private String name;
private char gender;
/ 员工类继承了Person类
@Entity
@Table(name="employee_inf")
public class Employee extends Person
{
// 定义该员工职位的成员变量
private String title;
// 定义该员工工资的成员变量
private double salary;
// 定义和该员工保持关联的Customer关联实体
@OneToMany(cascade=CascadeType.ALL
, mappedBy="employee" , targetEntity=Customer.class)
private Set<Customer> customers
= new HashSet<>();
// 定义和该员工保持关联的Manager关联实体
@ManyToOne(cascade=CascadeType.ALL
,targetEntity=Manager.class)
@JoinColumn(name="manager_id", nullable=true)
private Manager manager;