Hibernate学习笔记之继承映射

    技术2026-09-30  2

    Hibernate支持三种类型的继承关系:每个具体类一张表(Table per concrete class):表与子类之间的独立一对一关系。

    每个子类一张表(Table per subclass):每个子类对应一张子表,并与主类共享主表。

    每个类分层结构一张表(Table per class hierarchy):表与类的一对多关系。

    实例场景:产品(Product)、DVD和书籍(Book)

    1、每个具体类一张表。注解使用@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)表结构如下:

     

    @Entity @Table(name="t_product") @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) public class Product { private Integer id; private String manufacturer;//生产商 private String name;//商品名 @Id @GeneratedValue(strategy=GenerationType.AUTO) public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getManufacturer() { return manufacturer; } public void setManufacturer(String manufacturer) { this.manufacturer = manufacturer; } public String getName() { return name; } public void setName(String name) { this.name = name; } } @Entity @Table(name="t_dvd") public class DVD extends Product { private String regionCode; @Column(name="region_code") public String getRegionCode() { return regionCode; } public void setRegionCode(String regionCode) { this.regionCode = regionCode; } } @Entity @Table(name="t_book") public class Book extends Product { private Integer pageCount; @Column(name="page_count") public Integer getPageCount() { return pageCount; } public void setPageCount(Integer pageCount) { this.pageCount = pageCount; } } 

    测试方法:

    public void inheritanceTestInsert() { Product product1=new Product(); product1.setName("书籍"); product1.setManufacturer("出版商"); Product product2=new Product(); product2.setName("食品"); product2.setManufacturer("农场"); DVD dvd1=new DVD(); dvd1.setName("泰山"); dvd1.setManufacturer("北影"); dvd1.setRegionCode("美国"); DVD dvd2=new DVD(); dvd2.setName("让子弹飞"); dvd2.setManufacturer("大幅度"); dvd2.setRegionCode("中国"); Book book1=new Book(); book1.setName("大话"); book1.setManufacturer("备有"); book1.setPageCount(10000); Book book2=new Book(); book2.setName("托福"); book2.setManufacturer("科技"); book2.setPageCount(23434); Transaction tx=session.beginTransaction(); session.save(product1); session.save(product2); session.save(dvd1); session.save(dvd2); session.save(book1); session.save(book2); tx.commit(); }

     

    Hibernate生成的Sql语句:Hibernate: insert into t_product (manufacturer, name, id) values (?, ?, ?)Hibernate: insert into t_product (manufacturer, name, id) values (?, ?, ?)Hibernate: insert into t_dvd (manufacturer, name, region_code, id) values (?, ?, ?, ?)Hibernate: insert into t_dvd (manufacturer, name, region_code, id) values (?, ?, ?, ?)Hibernate: insert into t_book (manufacturer, name, page_count, id) values (?, ?, ?, ?)Hibernate: insert into t_book (manufacturer, name, page_count, id) values (?, ?, ?, ?)

     

    测试方法:

    public void inheritanceTestQuery() { Query query=session.createQuery("from Product"); List<Product> products=query.list(); }

    Hibernate生成的Sql语句:select product0_.id           as id6_,       product0_.manufacturer as manufact2_6_,       product0_.name         as name6_,       product0_.page_count   as page1_7_,       product0_.region_code  as region1_8_,       product0_.clazz_       as clazz_  from (select manufacturer,               null         as page_count,               null         as region_code,               name,               id,               0            as clazz_          from t_product        union all        select manufacturer,               page_count,               null         as region_code,               name,               id,               1            as clazz_          from t_book        union all        select manufacturer,               null         as page_count,               region_code,               name,               id,               2            as clazz_          from t_dvd) product0_Hibernate会自动把t_product,t_book和t_dvd表里的内容全部查询出来,这是因为Product类也是实体,在数据库中也有对应的表。如果不希望Product类成为映射实体,可以将其定义成抽象类(即public abstract class Product {})或者使用 @MappedSuperclass 注解,这样测试方法inheritanceTestQuery()对应Hibernate生成的sql语句为:select product0_.id           as id6_,       product0_.manufacturer as manufact2_6_,       product0_.name         as name6_,       product0_.page_count   as page1_7_,       product0_.region_code  as region1_8_,       product0_.clazz_       as clazz_  from (select manufacturer,               page_count,               null         as region_code,               name,               id,               1            as clazz_          from t_book        union all        select manufacturer,               null         as page_count,               region_code,               name,               id,               2            as clazz_          from t_dvd) product0_可见Hibernate只从t_dvd和t_book里取数据。

     

    2、每个子类一张表。注解使用@Inheritance(strategy=InheritanceType.JOINED)表结构

    @Entity @Table(name="t_product") @Inheritance(strategy=InheritanceType.JOINED) public class Product { private Integer id; private String manufacturer;//生产商 private String name;//商品名 @Id @GeneratedValue(strategy=GenerationType.AUTO) public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getManufacturer() { return manufacturer; } public void setManufacturer(String manufacturer) { this.manufacturer = manufacturer; } public String getName() { return name; } public void setName(String name) { this.name = name; } } @Entity @Table(name="t_dvd") public class DVD extends Product { private String regionCode; @Column(name="region_code") public String getRegionCode() { return regionCode; } public void setRegionCode(String regionCode) { this.regionCode = regionCode; } } @Entity @Table(name="t_book") public class Book extends Product { private Integer pageCount; @Column(name="page_count") public Integer getPageCount() { return pageCount; } public void setPageCount(Integer pageCount) { this.pageCount = pageCount; } }

     

    执行测试方法inheritanceTestInsert();Hibernate生成的Sql语句:Hibernate: insert into t_product (manufacturer, name, id) values (?, ?, ?)Hibernate: insert into t_product (manufacturer, name, id) values (?, ?, ?)Hibernate: insert into t_product (manufacturer, name, id) values (?, ?, ?)Hibernate: insert into t_dvd (region_code, id) values (?, ?)Hibernate: insert into t_product (manufacturer, name, id) values (?, ?, ?)Hibernate: insert into t_dvd (region_code, id) values (?, ?)Hibernate: insert into t_product (manufacturer, name, id) values (?, ?, ?)Hibernate: insert into t_book (page_count, id) values (?, ?)Hibernate: insert into t_product (manufacturer, name, id) values (?, ?, ?)Hibernate: insert into t_book (page_count, id) values (?, ?)

     

    执行测试方法inheritanceTestQuery() ;Hibernate生成的Sql语句:select product0_.id as id6_,       product0_.manufacturer as manufact2_6_,       product0_.name as name6_,       product0_1_.page_count as page2_7_,       product0_2_.region_code as region2_8_,       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_  from t_product product0_  left outer join t_book product0_1_    on product0_.id = product0_1_.id  left outer join t_dvd product0_2_    on product0_.id = product0_2_.idHibernate会自动把t_product、t_book与t_dvd表里的内容全部连接查询出来。

     

     

    3、每个类分层结构一张表。注解使用@Inheritance(strategy=InheritanceType.SINGLE_TABLE)表结构

     

    @Entity @Table(name="t_product") @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name="category",discriminatorType=DiscriminatorType.STRING)//定义用于区分的列名为category,列类型为String @DiscriminatorValue("product")//可选,指定Product类对应的记录的category字段的值为“product”,默认值为类名,即"Product" public class Product { private Integer id; private String manufacturer;//生产商 private String name;//商品名 @Id @GeneratedValue(strategy=GenerationType.AUTO) public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getManufacturer() { return manufacturer; } public void setManufacturer(String manufacturer) { this.manufacturer = manufacturer; } public String getName() { return name; } public void setName(String name) { this.name = name; } } @Entity @DiscriminatorValue("dvd")//可选,指定DVD类对应的记录的category字段的值为“dvd”,默认值为类名,即"DVD" public class DVD extends Product { private String regionCode; @Column(name="region_code") public String getRegionCode() { return regionCode; } public void setRegionCode(String regionCode) { this.regionCode = regionCode; } } @Entity @DiscriminatorValue("book")//可选,指定Book类对应的记录的category字段的值为“book”,默认值为类名,即"Book" public class Book extends Product { private Integer pageCount; @Column(name="page_count") public Integer getPageCount() { return pageCount; } public void setPageCount(Integer pageCount) { this.pageCount = pageCount; } }

     

    执行测试方法inheritanceTestInsert();Hibernate生成的sql语句:Hibernate: insert into t_product (manufacturer, name, category, id) values (?, ?, 'product', ?)Hibernate: insert into t_product (manufacturer, name, category, id) values (?, ?, 'product', ?)Hibernate: insert into t_product (manufacturer, name, region_code, category, id) values (?, ?, ?, 'dvd', ?)Hibernate: insert into t_product (manufacturer, name, region_code, category, id) values (?, ?, ?, 'dvd', ?)Hibernate: insert into t_product (manufacturer, name, page_count, category, id) values (?, ?, ?, 'book', ?)Hibernate: insert into t_product (manufacturer, name, page_count, category, id) values (?, ?, ?, 'book', ?)可见,Product、DVD和Book对应的记录都插入了t_product表中,并通过category字段来区分。

     执行测试方法

    public void inheritanceTestQuery() { Query query=session.createQuery("from Book"); List<Product> products=query.list(); } Hibernate生成的Sql语句:select book0_.id           as id6_,       book0_.manufacturer as manufact3_6_,       book0_.name         as name6_,       book0_.page_count   as page5_6_  from t_product book0_ where book0_.category = 'book'Hibernate会根据配置自动进行类型识别,把t_product表中category=book的数据(Book) 全部查询出来。

    最新回复(0)