hibernate单表继承映射

来源:互联网 发布:java基础 编辑:程序博客网 时间:2024/04/29 09:47

实际开发中,有这么一种情况:有一个父类Person,它有两个子类:Teacher和Student都继承了Person ,如图:



我们可以把这种关系的数据,设计到一张表中展示,如图:


现在我们就来看一下,怎么样来写实体类和对应的映射关系来生成上面这张表,


新建一个java项目,结构如下:



jar和hibernate官网获取方法,请参见《Hibernate环境搭建和配置


Person代码:

package com.robert.pojo;public class Person {private int id ;private String name ;private int age ;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}


Student类代码:

package com.robert.pojo;public class Student extends Person {private String work ;public String getWork() {return work;}public void setWork(String work) {this.work = work;}}

Teacher类代码:

package com.robert.pojo;public class Teacher extends Person {private int salary ;public int getSalary() {return salary;}public void setSalary(int salary) {this.salary = salary;}}


Person.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.robert.pojo"><class name="Person"><id name="id" column="id"><generator class="native"></generator></id><!-- discriminator指明鉴别器column:数据库表字段,用来区分不同的子类subclass,具体的数值,来源于不同的subclass中的discriminator-value --><discriminator column="type" type="string" /><property name="name" /><property name="age" /><subclass name="Student" discriminator-value="s"><property name="work" /></subclass><subclass name="Teacher" discriminator-value="t"><property name="salary" /></subclass></class></hibernate-mapping>

HibernateUtil代码:

package com.robert.util;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.boot.registry.StandardServiceRegistryBuilder;import org.hibernate.cfg.Configuration;/** * hibernate工具类 */public class HibernateUtil {private static Configuration cfg = null;private static SessionFactory factory = null;private static Session session = null ;static {init();}/** * 初始化获得Configuration和SessionFacroty对象 */public static void init() {cfg = new Configuration().configure();factory = cfg.buildSessionFactory(new StandardServiceRegistryBuilder().applySettings(cfg.getProperties()).build());}/** * 获得Session对象 * @return */public static Session getSession() {if (factory != null){return session = factory.openSession();}init();return session = factory.openSession();}/** * 关闭Session */public static void closeSession() {if(session!=null && session.isOpen())session.close();}}

hibernate.cfg.xml代码:

<!DOCTYPE hibernate-configuration PUBLIC"-//Hibernate/Hibernate Configuration DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"><hibernate-configuration><session-factory><!-- 配置数据库连接信息 --><property name="connection.driver_class">com.mysql.jdbc.Driver</property><property name="connection.url">jdbc:mysql:///hibernate4</property><property name="connection.username">root</property><property name="connection.password">root</property><!-- 数据库方言 --><property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property><!-- 是否打印sql语句 --><property name="show_sql">true</property><!-- 格式化sql语句 --><property name="format_sql">true</property><!-- 数据库更新方式: 1、create:每次更新都先把原有数据库表删除,然后创建该表;2、create-drop:使用create-drop时,在显示关闭SessionFacroty时(sessionFactory.close()),将drop掉数据库Schema(表) 3、validate:检测;4、update(常用):如果表不存在则创建,如果存在就不创建--><property name="hbm2ddl.auto">update</property><mapping resource="com/robert/pojo/Person.hbm.xml"/></session-factory></hibernate-configuration>


HibernateTest代码:


package com.robert.test;import java.io.IOException;import java.sql.SQLException;import javax.sql.rowset.serial.SerialException;import org.hibernate.HibernateException;import org.hibernate.Session;import org.hibernate.Transaction;import org.hibernate.cfg.Configuration;import org.hibernate.tool.hbm2ddl.SchemaExport;import org.junit.Test;import com.robert.pojo.Person;import com.robert.pojo.Student;import com.robert.pojo.Teacher;import com.robert.util.HibernateUtil;public class HibernateTest {/** * 根据*.hbm.xml文件对应的生成数据库表 */@Testpublic void testCreateDB() {Configuration cfg = new Configuration().configure();SchemaExport se = new SchemaExport(cfg);// 第一个参数:是否生成ddl脚本// 第二个参数:是否执行到数据库中se.create(true, true);}/** * 保存数据 *  * @throws HibernateException * @throws SerialException * @throws SQLException * @throws IOException */@Testpublic void testSave() throws HibernateException, SerialException,SQLException, IOException {Session session = null;Transaction tx = null;try {session = HibernateUtil.getSession();tx = session.beginTransaction();Teacher t1 = new Teacher() ;t1.setAge(32) ;t1.setName("张老师") ;t1.setSalary(5000) ;Student stu1 = new Student() ;stu1.setAge(22) ;stu1.setName("王同学") ;stu1.setWork("家庭作业1") ;Student stu2 = new Student() ;stu2.setAge(24) ;stu2.setName("刘同学") ;stu2.setWork("housework") ;session.save(t1) ;session.save(stu1) ;session.save(stu2) ;tx.commit();} catch (HibernateException e) {if (tx != null) {tx.rollback();}e.printStackTrace();throw e;} finally {HibernateUtil.closeSession();}}/** * get获取数据 */@Testpublic void testGet() {Session session = null;Transaction tx = null;try {session = HibernateUtil.getSession();tx = session.beginTransaction();Person person = (Person) session.get(Person.class, 2) ;System.out.println("name="+person.getName());//session的get方法得到的person是他的子类//但是load方法得到的是子类的代理类,所以load方法,不可以使用instanceof方法判断类型if(person instanceof Student) {Student stu = (Student) person ;System.out.println("work="+stu.getWork());}// 取数据tx.commit();} catch (Exception e) {tx.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession();}}/** * load获取数据 */@Testpublic void testLoad() {Session session = null;Transaction tx = null;try {session = HibernateUtil.getSession();tx = session.beginTransaction();Person person = (Person) session.load(Person.class, 2) ;System.out.println("name="+person.getName());//session的get方法得到的person是他的子类//但是load方法得到的是子类的代理类,所以load方法,不可以使用instanceof方法判断类型//if(person instanceof Student) {//Student stu = (Student) person ;//System.out.println("work="+stu.getWork());//}// 取数据tx.commit();} catch (Exception e) {tx.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession();}}}


关于session的get和load方法返回的类型和代理问题,如图:

get方法返回的是真正的类



laod方法返回的是代理类




保存后数据库数据为:



测试自己测试即可,我就不贴测试结果过程和图了


总结:

1、在单表继承映射中,hibernate通过鉴别器来识别子类的类型,鉴别器由hibernate来经行维护。

2、查询数据时,如果使用get查询得到的数据类型可以经行多态判断;如果使用load查询,load是懒加载(lazy),返回的是代理类。

3、Person.hbm.xml中子类的配置还有一种形式:

就是将subclass放到class外面,使用extends属性,来继承class

如图:















原创粉丝点击