JPA对象关系-继承
JPA对象关系-继承
比如我们需要设计一组表结构存储电商中的商品、手机和衣服这样的数据。
他们之间都有一些通用的属性,比如名称、价格等等,但是又有一些特殊的属性,比如手机有型号,衣服有颜色(当然手机也有颜色,这里只是作为案例,不要太苛刻)等特殊属性。
设置的类型可能就是公用属性抽到1个类里面,特殊的属性独自1个类里面。如下3个类型结构,但是数据库表如何设计?
1、表的设计-每个类单独1个表(多用)InheritanceType.TABLE_PER_CLASS
多态查询
效率极低- 可以保证数据完整性,并且新增操作表少
- 不用多态查询时,效率高,开发时尽量避免。一般使用这种方式
2、表的设计-每个子类
单独1个表InheritanceType.JOINED
每个子类1个表,但是ID有主表控制,子类的ID必和主表某条ID一致
问题:新增或查询需要操作多张表,性能低
3、表的设计-所有信息放到1个表中 InheritanceType.SINGLE_TABLE 默认
- 表列很多,并且大部分类不能做
非空约束
,不能保证数据完整性 - 需要添加
额外的列
来记录当前商品是什么类型 - 随着时间,数据量越来越大,查询性能下降
类型定义
@Data
@Entity
public class Product {
@Id
@GeneratedValue
private long id;
private String name;
}
@Data
@Entity
public class Phone extends Product {
private String xhao;
}
@Data
@Entity
public class Cloth extends Product {
private String color;
}
persistence.xml配置
<class>com.hongying.entity.extend.Product</class>
<class>com.hongying.entity.extend.Phone</class>
<class>com.hongying.entity.extend.Cloth</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
单元测试保存
@Test
public void save(){
Product p=new Product();
p.setName("冰淇淋");
Phone phone=new Phone();
phone.setName("华为手机");
phone.setXhao("P7");
Cloth cloth=new Cloth();
cloth.setName("七匹狼内裤");
cloth.setColor("red");
//保存
EntityManager entityManager = JpaUtil.getEntityManager();
entityManager.getTransaction().begin();
entityManager.persist(p);
entityManager.persist(phone);
entityManager.persist(cloth);
entityManager.getTransaction().commit();
entityManager.close();
}
运行保存,查看结果
可见JPA,默认使用的是第3中,所有商品放到1个表中。默认添加类型列DTYPE
存储类型名称
InheritanceType.SINGLE_TABLE 详细使用-默认
类型定义
@Data
@Entity
//默认 所有子类都放到1个类型中
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
//指定鉴别器(商品类型)列的名称和值
@DiscriminatorColumn(name = "type")
@DiscriminatorValue(value = "1")
public class Product {
@Id
@GeneratedValue
private long id;
private String name;
}
@Data
@Entity
@DiscriminatorValue(value = "2")
public class Phone extends Product {
private String xhao;
}
@Data
@Entity
@DiscriminatorValue(value = "3")
public class Cloth extends Product {
private String color;
}
查询
@Test
public void find()
{
EntityManager entityManager = JpaUtil.getEntityManager();
Phone phone = entityManager.find(Phone.class, 2L);
System.out.println("phone = " + phone);
entityManager.close();
}
select phone0_.id as id2_0_0_, phone0_.name as name3_0_0_, phone0_.xhao as xhao4_0_0_ from Product phone0_ where phone0_.id=? and phone0_.type='2'
InheritanceType.TABLE_PER_CLASS 使用详解
类型定义
@Data
@Entity
//每个子类生成一个表
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Product {
/**
* Cannot use identity column key generation with <union-subclass> mapping for
* 使用这种类型时,主键生成策略就不能自增了,需要单独1个包维护主键,否则异常
*/
@Id
// @GeneratedValue
@GeneratedValue(strategy = GenerationType.TABLE)
private long id;
private String name;
}
@Data
@Entity
public class Phone extends Product {
private String xhao;
}
@Data
@Entity
public class Cloth extends Product {
private String color;
}
单独查找指定子类时,比较快
@Test
public void find()
{
EntityManager entityManager = JpaUtil.getEntityManager();
Phone phone = entityManager.find(Phone.class, 2L);
System.out.println("phone = " + phone);
entityManager.close();
}
select phone0_.id as id1_2_0_, phone0_.name as name2_2_0_, phone0_.xhao as xhao1_1_0_ from Phone phone0_ where phone0_.id=?
多态查询
多态查询时,会把所有子表都Union,然后子查询,性能低。使用这种时,尽量避免多态查询方式
@Test
public void find()
{
EntityManager entityManager = JpaUtil.getEntityManager();
//指定父类时,按照父类查询,结果还是强子类类型
Product phone = entityManager.find(Product.class, 2L);
System.out.println("phone = " + phone);
entityManager.close();
}
select product0_.id as id1_2_0_, product0_.name as name2_2_0_, product0_.xhao as xhao1_1_0_, product0_.color as color1_0_0_, product0_.clazz_ as clazz_0_ from (
select id, name, null as xhao, null as color, 0 as clazz_
from Product
union
select id, name, xhao, null as color, 1 as clazz_
from Phone
union
select id, name, null as xhao, color, 2 as clazz_
from Cloth
) product0_ where product0_.id=?
phone = Phone(xhao=P7)
InheritanceType.JOINED 详解
父类通用数据存储到1个表,子类独立数据存储到1个表。查询时left outer join 查询
类型定义
@Data
@Entity
//子类单独1个表,通用数据都放到父表中
@Inheritance(strategy = InheritanceType.JOINED)
public class Product {
@Id
@GeneratedValue
private long id;
private String name;
}
@Data
@Entity
public class Phone extends Product {
private String xhao;
}
@Data
@Entity
public class Cloth extends Product {
private String color;
}
查询
@Test
public void find()
{
EntityManager entityManager = JpaUtil.getEntityManager();
Product phone = entityManager.find(Product.class, 2L);
System.out.println("phone = " + phone);
entityManager.close();
}
}
select product0_.id as id1_2_0_, product0_.name as name2_2_0_, product0_1_.xhao as xhao1_1_0_, product0_2_.color as color1_0_0_,
case
when product0_1_.id is not null then 1
when product0_2_.id is not null then 2
when product0_.id is not null then 0 end as clazz_0_
from Product product0_
left outer join Phone product0_1_ on product0_.id=product0_1_.id
left outer join Cloth product0_2_ on product0_.id=product0_2_.id
where product0_.id=?
phone = Phone(xhao=P7)