10、JPA对象关系-继承

本文探讨了JPA中对象关系继承的三种策略:表格分离(TABLE_PER_CLASS)、联合子类(JOINED)和单一表(SINGLE_TABLE)。讲解了它们在表设计、查询性能和多态查询上的优缺点,以及如何通过配置和实例展示来实现不同类型的继承。
摘要由CSDN通过智能技术生成

JPA对象关系-继承

比如我们需要设计一组表结构存储电商中的商品、手机和衣服这样的数据。
他们之间都有一些通用的属性,比如名称、价格等等,但是又有一些特殊的属性,比如手机有型号,衣服有颜色(当然手机也有颜色,这里只是作为案例,不要太苛刻)等特殊属性。
设置的类型可能就是公用属性抽到1个类里面,特殊的属性独自1个类里面。如下3个类型结构,但是数据库表如何设计?
在这里插入图片描述

1、表的设计-每个类单独1个表(多用)InheritanceType.TABLE_PER_CLASS

  1. 多态查询效率极低
  2. 可以保证数据完整性,并且新增操作表少
  3. 不用多态查询时,效率高,开发时尽量避免。一般使用这种方式
    在这里插入图片描述

2、表的设计-每个子类单独1个表InheritanceType.JOINED

每个子类1个表,但是ID有主表控制,子类的ID必和主表某条ID一致
问题:新增或查询需要操作多张表,性能低
在这里插入图片描述

3、表的设计-所有信息放到1个表中 InheritanceType.SINGLE_TABLE 默认

  1. 表列很多,并且大部分类不能做非空约束,不能保证数据完整性
  2. 需要添加额外的列来记录当前商品是什么类型
  3. 随着时间,数据量越来越大,查询性能下降
    在这里插入图片描述

类型定义

@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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值