每个类映射一张表(3张表)
父类和子类都各对应一张表。那么就有三张表了
这种结构看起来是完全面向对象,但是表之间的结构会很复杂,插入一条子类的信息,需要两条SQL
数据表设计
这里写图片描述
映射文件
使用到了<joined-subclass >
这个节点
<?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="zhongfucheng.aa"> <class name="Animal" table="t_animal"> <id name="id"> <generator class="native"></generator> </id> <property name="name"></property> <!-- Animal下的子类映射成一张表 指定子类的类型,对应的表 指定子类的外键字段【需要对应Animal】 指定子类的普通属性 --> <joined-subclass name="Cat" table="cat_"> <!--key对应的是外键字段--> <key column="animal_id"></key> <property name="catchMouse"></property> </joined-subclass> <joined-subclass name="Monkey" table="monkey_"> <!--key对应的是外键字段--> <key column="animal_id"></key> <property name="eatBanana"></property> </joined-subclass> </class> </hibernate-mapping>
测试
package zhongfucheng.aa; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.hibernate.classic.Session; public class App5 { public static void main(String[] args) { //创建对象 Cat cat = new Cat(); Monkey monkey = new Monkey(); //设置属性 cat.setName("大花猫"); cat.setCatchMouse("小老鼠"); monkey.setEatBanana("吃香蕉"); monkey.setName("大猴子"); //获取加载配置管理类 Configuration configuration = new Configuration(); //加载类对应的映射文件! configuration.configure().addClass(Animal.class); //创建Session工厂对象 SessionFactory factory = configuration.buildSessionFactory(); //得到Session对象 Session session = factory.openSession(); //使用Hibernate操作数据库,都要开启事务,得到事务对象 Transaction transaction = session.getTransaction(); //开启事务 transaction.begin(); session.save(cat); session.save(monkey); //提交事务 transaction.commit(); //关闭Session session.close(); } }
每保存一个子类对象需要两条SQL语句!
这里写图片描述
(推荐)每个子类映射一张表, 父类不对应表(2张表)
-
使用过了一张表保存所有子类的数据,这不符合数据库设计规范
-
每个子类、父类都拥有一张表..表结构太过于繁琐..添加信息时,过多的SQL
我们即将使用的是:每个子类映射成一张表,父类不对应表…这和我们传统方式继承是一样的。只不过在hbm.xml文件中使用了<union-subclass>
这个节点,由于有了这个节点,我们就不需要每个子类都写一个配置文件了。
数据库表设计
这里写图片描述
映射文件
-
想要父类不映射成数据库表,只要在class中配置为abstract即可
-
使用了union-subclass节点,主键就不能采用自动增长策略了。我们改成UUID即可。当然啦,对应的实体id类型要改成String
<?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="zhongfucheng.aa"> <!-- 想要父类不映射成表,设置成abstract --> <class name="Animal" abstract="true"> <!-- 如果使用了union-subclass节点,那么主键生成策略不能是自增长,我们改成uuid即可 --> <id name="id"> <generator class="uuid"></generator> </id> <property name="name"></property> <!-- 将子类的信息都映射成一张表 给出属性的名称 属性对应的数据库表 普通字段 --> <union-subclass name="Cat" table="cat_"> <property name="catchMouse"></property> </union-subclass> <union-subclass name="Monkey" table="monkey_"> <property name="eatBanana"></property> </union-subclass> </class> </hibernate-mapping>
测试
package zhongfucheng.aa; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.hibernate.classic.Session; public class App5 { public static void main(String[] args) { //创建对象 Cat cat = new Cat(); Monkey monkey = new Monkey(); //设置属性 cat.setName("大花猫"); cat.setCatchMouse("小老鼠"); monkey.setEatBanana("吃香蕉"); monkey.setName("大猴子"); //获取加载配置管理类 Configuration configuration = new Configuration(); //加载类对应的映射文件! configuration.configure().addClass(Animal.class); //创建Session工厂对象 SessionFactory factory = configuration.buildSessionFactory(); //得到Session对象 Session session = factory.openSession(); //使用Hibernate操作数据库,都要开启事务,得到事务对象 Transaction transaction = session.getTransaction(); //开启事务 transaction.begin(); session.save(cat); session.save(monkey); //提交事务 transaction.commit(); //关闭Session session.close(); } }
这里写图片描述
组件映射和继承映射总结
由于我们的传统继承映射每个子类都对应一个配置文件,这样十分麻烦。因此.hbm.xml就给出了几个节点供我们使用,分别有以下的情况:
- 子类父类共有一张表
subclass
- 不符合数据库设计规范
- 需要使用鉴别器
- 子类、父类都有自己的表
joined-subclass
,那么就是三张表
- 表的结构太过繁琐
- 插入数据时要生成SQL至少就要两条
-
子类拥有自己的表、父类不对应表【推荐】
union-subclass
- 父类不对应表要使用abstract来修饰
- 主键的id不能使用自增长策略,修改成UUID就好了。对应的JavaBean的id设置成String就好