继承映射: 类有继承的概念, 表是没有继承的概念的, 但是可以体现这种关系
首先, 新建三个类, 分别是Animal类/Pig类/Bird类, 它们之间的关系是Pig类继承Animal类/Bird类继承Animal类, 然后建立映射关系
工程结构如图:
①单表继承映射(缺点: 出现冗余字段)
将这些属性存储在一张表中:
anId | anName | gender | weight | height | type |
1 | 八戒 | 1 | 300 | P | |
2 | 大鹏 | 1 | 10000 | B |
添加:
"Animal.hbm.xml"配置文件:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.rl.hiber.model">
<class name="Animal" table="t_animal">
<!-- 父类的配置
-->
<id name="anId" column="an_id">
<!--
identity(常用): 使用mysql的自增策略, 这种自增没有并发问题, 前提是model的oid是数值类型, 所映射的column也是数值类型
native(比较智能): 根据数据库的方言来翻译, 自动翻译成identity(mysql)或sequence(oracle)
uuid(有大量使用, 由于没有锁机制, 性能较高): 没有并发问题, 按照自己的策略生成一个32位的字符串, 主键不重复, 前提是主键(oid)必须是字符串类型
assigned: 手动指定id(在实际项目中不使用)
increment: 主键自动自增(在实际项目中不去使用, 因为有并发安全性问题)
-->
<generator class="native"></generator>
</id>
<!-- 设置鉴别器
用于区别是Pig还是Bird(在t_animal表设置一个type的字段)
-->
<discriminator column="type" type="string"></discriminator>
<property name="anName" column="an_name"></property>
<property name="gender"></property>
<!-- 子类的配置
name: 子类的类名
discriminator-value: 区分子类的字段
name: 子类的字段映射
-->
<subclass name="Pig" discriminator-value="p">
<property name="weight"></property>
</subclass>
<subclass name="Bird" discriminator-value="b">
<property name="height"></property>
</subclass>
</class>
</hibernate-mapping>
生成数据库表(1张表):
插入数据:
测试代码:
package com.rl.hiber.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.rl.hiber.model.Bird;
import com.rl.hiber.model.Pig;
import com.rl.hiber.utils.HibernateUtil;
public class TestHibernate {
@Test
public void test1(){
Session session = HibernateUtil.getSessoion();
Transaction tx = session.beginTransaction();
try {
Pig pig = new Pig();
pig.setAnName("天蓬元帅");
pig.setGender(1);
pig.setWeight(300);
session.save(pig);
Bird bird = new Bird();
bird.setAnName("大鹏");
bird.setGender(1);
bird.setHeight(10000);
session.save(bird);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally{
HibernateUtil.closeResource(session);
}
}
}
控制台输出:
Hibernate: insert into t_animal (an_name, gender, weight, type) values (?, ?, ?, 'p')
Hibernate: insert into t_animal (an_name, gender, height, type) values (?, ?, ?, 'b')
数据库结果:
查询:
查询子类:
测试代码:
@Test
public void test2(){
Session session = HibernateUtil.getSessoion();
try {
Pig pig = (Pig) session.load(Pig.class, 1);
System.out.println(pig.getAnName()+" "+pig.getWeight());
} catch (Exception e) {
e.printStackTrace();
}finally{
HibernateUtil.closeResource(session);
}
}
控制台输出:
Hibernate: select pig0_.an_id as an_id1_0_0_, pig0_.an_name as an_name3_0_0_, pig0_.gender as gender4_0_0_, pig0_.weight as weight5_0_0_ from t_animal pig0_ where pig0_.an_id=? and pig0_.type='p'
天蓬元帅 300
查询父类:
测试代码:
/**
* load的延迟加载返回的是代理类, 所以无法完成多态(父类)查询
*/
@Test
public void test3(){
Session session = HibernateUtil.getSessoion();
try {
Animal animal = (Animal) session.load(Animal.class, 1);
if(animal instanceof Pig){
System.out.println("是猪");
}else{
System.out.println("不是猪");
}
} catch (Exception e) {
e.printStackTrace();
}finally{
HibernateUtil.closeResource(session);
}
}
/**
* get是急加载方式, 所以能够知道是Pig类型, 直接可以强转输出
*/
@Test
public void test4(){
Session session = HibernateUtil.getSessoion();
try {
Animal animal = (Animal) session.get(Animal.class, 1);
if(animal instanceof Pig){
System.out.println("是猪");
Pig pig = (Pig)animal;
System.out.println(pig.getAnName() + " "+pig.getWeight());
}else{
System.out.println("不是猪");
}
} catch (Exception e) {
e.printStackTrace();
}finally{
HibernateUtil.closeResource(session);
}
}
get方式的控制台输出:
Hibernate: select animal0_.an_id as an_id1_0_0_, animal0_.an_name as an_name3_0_0_, animal0_.gender as gender4_0_0_, animal0_.weight as weight5_0_0_, animal0_.height as height6_0_0_, animal0_.type as type2_0_0_ from t_animal animal0_ where animal0_.an_id=?
是猪
天蓬元帅 300
②父子表继承映射(无冗余字段, 但效率比①较低)
顾名思义: 父类和子类各自一张表(父类产生父类的表, 子类产生子类的表)
"Animal1.hbm.xml"配置文件:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.rl.hiber.model">
<class name="Animal" table="t_animal">
<!-- 父类的配置
-->
<id name="anId" column="an_id">
<generator class="native"></generator>
</id>
<property name="anName" column="an_name"></property>
<property name="gender"></property>
<!-- 子类的配置
name: 子表的类名
table: 子表的表名
key: 子表中对应的主键id
property: 映射属性
-->
<joined-subclass name="Pig" table="t_pig">
<key column="pid"></key>
<property name="weight"></property>
</joined-subclass>
<joined-subclass name="Bird" table="t_bird">
<key column="bid"></key>
<property name="height"></property>
</joined-subclass>
</class>
</hibernate-mapping>
生成数据库表(3张表):
插入数据:
测试代码不变:
@Test
public void test1(){
Session session = HibernateUtil.getSessoion();
Transaction tx = session.beginTransaction();
try {
Pig pig = new Pig();
pig.setAnName("天蓬元帅");
pig.setGender(1);
pig.setWeight(300);
session.save(pig);
Bird bird = new Bird();
bird.setAnName("大鹏");
bird.setGender(1);
bird.setHeight(10000);
session.save(bird);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally{
HibernateUtil.closeResource(session);
}
}
控制台输出:
Hibernate: insert into t_animal (an_name, gender) values (?, ?)
Hibernate: insert into t_pig (weight, pid) values (?, ?)
Hibernate: insert into t_animal (an_name, gender) values (?, ?)
Hibernate: insert into t_bird (height, bid) values (?, ?)
数据库结果:
查询:
查询的方式跟①相同, 但是由于父子表的映射生成的表有多张, 所以查询时需要多张表连接查询, 效率较①低
Hibernate: select pig0_.pid as an_id1_0_0_, pig0_1_.an_name as an_name2_0_0_, pig0_1_.gender as gender3_0_0_, pig0_.weight as weight2_2_0_ from t_pig pig0_ inner join t_animal pig0_1_ on pig0_.pid=pig0_1_.an_id where pig0_.pid=?
Hibernate: select animal0_.an_id as an_id1_0_0_, animal0_.an_name as an_name2_0_0_, animal0_.gender as gender3_0_0_, animal0_1_.weight as weight2_2_0_, animal0_2_.height as height2_1_0_, case when animal0_1_.pid is not null then 1 when animal0_2_.bid is not null then 2 when animal0_.an_id is not null then 0 end as clazz_0_ from t_animal animal0_ left outer join t_pig animal0_1_ on animal0_.an_id=animal0_1_.pid left outer join t_bird animal0_2_ on animal0_.an_id=animal0_2_.bid where animal0_.an_id=?
是猪
天蓬元帅 300
③子表继承映射
"Animal2.hbm.xml"配置文件:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.rl.hiber.model">
<class name="Animal" table="t_animal" abstract="true">
<!-- 父类的配置
-->
<id name="anId" column="an_id">
<!-- 采用子表继承映射的方式则必须将主键的生成策略设置成"uuid"
-->
<generator class="uuid"></generator>
</id>
<property name="anName" column="an_name"></property>
<property name="gender"></property>
<!-- 子表映射配置
-->
<union-subclass name="Pig" table="t_pig">
<property name="weight"></property>
</union-subclass>
<union-subclass name="Bird" table="t_bird">
<property name="height"></property>
</union-subclass>
</class>
</hibernate-mapping>
注意: Animal类也需要将anId改为String类型
数据表生成:
插入数据:
测试代码:
跟①相同
控制台输出结果:
Hibernate: insert into t_pig (an_name, gender, weight, an_id) values (?, ?, ?, ?)
Hibernate: insert into t_bird (an_name, gender, height, an_id) values (?, ?, ?, ?)
数据库结果:
查询:
跟①相同