Hibernate深入学习(三):继承与多态查询,joined-subclass与union-subclass

本文深入探讨Hibernate中的joined-subclass和union-subclass继承方式,分析它们的实体映射、数据库操作(插入、查询)以及各自的优缺点。通过实例展示了如何进行查询,并指出这两种继承方式在效率上的挑战。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在上一篇中,我们对hibernate中3种继承有了初步了解,并对subclass进行了测试,以及知道了它的诸多缺点,这些缺点导致subclass在开发中并不常用,接下来我们看看剩下的两种继承方式:joined-subclass与union-subclass

本文中使用的实体类与测试代码同前篇,不再赘述

首先我们看看joined-class的实体映射文件:主要看元素

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.sina.join.subclass" auto-import="false">
    <class name="Person" table="joined_person">
        <id name="id" column="pid" length="10" type="java.lang.Integer">
            <generator class="increment"></generator>
        </id>
        <property name="name" type="java.lang.String" length="32" not-null="true"></property>
        <property name="age" type="java.lang.Integer" length="5" not-null="true"></property>

        <joined-subclass name="Worker" table="joined_worker">
            <key column="person_id"></key>
            <property name="job" type="java.lang.String" length="32"></property>
            <property name="unit" type="java.lang.String" length="32"></property>
        </joined-subclass>
    </class>
</hibernate-mapping>

我们已经知道joined-subclass是会产生两张表的,中的table用于指定子类表名,并且使用person_id来与父类表建立关联

测试代码见前篇,插入的测试结果如下:

Hibernate: 
    select
        max(pid) 
    from
        joined_person
Hibernate: 
    insert 
    into
        joined_person
        (name, age, pid) 
    values
        (?, ?, ?)
Hibernate: 
    insert 
    into
        joined_person
        (name, age, pid) 
    values
        (?, ?, ?)
Hibernate: 
    insert 
    into
        joined_worker
        (job, unit, person_id) 
    values
        (?, ?, ?)

可以看到发出了4条sql语句,除了第一句省略,其它共3条insert语句
因为joined-subclass采用的是父类表存储父类字段,子类表存储子类字段,用外键关联,
因此第一条insert语句对应的是session.save(person);
第二天insert语句是在 session.save(worker)时,将worker继承自父类的字段插入,
最后一条insert语句是插入将worker插入到子类表中,它直插入子类独有的字段

在做查询时,请使用类全名的形式,例如:

session.createQuery("from cn.sina.join.subclass.Person").list();

查询的结果如下:

Hibernate: 
    select
        person0_.pid as pid1_,
        person0_.name as name1_,
        person0_.age as age1_,
        person0_1_.job as job2_,
        person0_1_.unit as unit2_,
        case 
            when person0_1_.person_id is not null then 1 
            when person0_.pid is not null then 0 
        end as clazz_ 
    from
        joined_person person0_ 
    left outer join
        joined_worker person0_1_ 
            on person0_.pid=person0_1_.person_id
Hibernate: 
    select
        worker0_.person_id as pid1_,
        worker0_1_.name as name1_,
        worker0_1_.age as age1_,
        worker0_.job as job2_,
        worker0_.unit as unit2_ 
    from
        joined_worker worker0_ 
    inner join
        joined_person worker0_1_ 
            on worker0_.person_id=worker0_1_.pid
[Person [id=1, name=tom, age=10], Worker [job=washer, unit=bj], Person [id=3, name=tom, age=10], Worker [job=washer, unit=bj]]
[Worker [job=washer, unit=bj], Worker [job=washer, unit=bj]]

可以看出查询父类使用的是一个左外连接查询,同时查询出了子类,而查询子类使用的是一个内连接查询


最后一个是union-subclass,它和joined-subclass类似,它将父类对应一张表,子类对应一张表,此时的子类表包括了从父类中继承的字段,它的实体映射文件如下:注意看

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.sina.union.subclass" auto-import="false">
    <class name="Person" table="union_person">
        <id name="id" column="pid" length="10" type="java.lang.Integer">
            <generator class="increment"></generator>
        </id>
        <property name="name" type="java.lang.String" length="32" not-null="true"></property>
        <property name="age" type="java.lang.Integer" length="5" not-null="true"></property>

        <union-subclass name="Worker" table="union_worker">
            <property name="job" type="java.lang.String" length="32"></property>
            <property name="unit" type="java.lang.String" length="32"></property>
        </union-subclass>
    </class>
</hibernate-mapping>

可以看出union-subclass只需要指定一个表名即可

插入测试结果很简单,就是发出两条inert语句,插入到对应的表中即可

Hibernate: 
    select
        max(ids_.pid) 
    from
        ( select
            pid 
        from
            union_person 
        union
        select
            pid 
        from
            union_worker 
    ) ids_
Hibernate: 
    insert 
    into
        union_person
        (name, age, pid) 
    values
        (?, ?, ?)
Hibernate: 
    insert 
    into
        union_worker
        (name, age, job, unit, pid) 
    values
        (?, ?, ?, ?, ?)

查询结果如下(hql也要使用类全名)

Hibernate: 
    select
        person0_.pid as pid3_,
        person0_.name as name3_,
        person0_.age as age3_,
        person0_.job as job4_,
        person0_.unit as unit4_,
        person0_.clazz_ as clazz_ 
    from
        ( select
            pid,
            name,
            age,
            null as job,
            null as unit,
            0 as clazz_ 
        from
            union_person 
        union
        select
            pid,
            name,
            age,
            job,
            unit,
            1 as clazz_ 
        from
            union_worker 
    ) person0_
Hibernate: 
    select
        worker0_.pid as pid3_,
        worker0_.name as name3_,
        worker0_.age as age3_,
        worker0_.job as job4_,
        worker0_.unit as unit4_ 
    from
        union_worker worker0_
[Person [id=1, name=tom, age=10], Worker [job=washer, unit=bj]]
[Worker [job=washer, unit=bj]]

我们着重看一下父类的查询sql,比较有意思,它也将子类查询出来了,它先通过union将两张表联合查询,再从联合查询的结果中获取结果。

最后分析下二者的缺点:
1.插入与查询的效率都低下
2.union-subclass在更新父类表时效率低下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值