“每个具体类一张表”的意思是:使继承体系中每一个子类都对应数据库中的一张表。每一个子类对应的数据库表都包含了父类的信息,并且包含了自己独有的属性。每个子类对应一张表,而且这个表的信息是完备的,即包含了所有从父类继承下来的属性映射的字段。这种策略是使用<union-subclass>标签来定义子类的。
通过mysql建立worker表和student表
Person类:
package com.hiberbate.manytomany;
public class Person {
private int id;
private String name;
private int age;
private String sex;
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;
}
public String getSex(){
return sex;
}
public void setSex(String sex){
this.sex = sex;
}
}
Student类:
package com.hiberbate.manytomany;
public class Student extends Person{
private String sno;
private String school;
public String getSno(){
return sno;
}
public void setSno(String sno){
this.sno = sno;
}
public String getSchool(){
return school;
}
public void setSchool(String school){
this.school = school;
}
}
Worker类:
package com.hiberbate.manytomany;
public class Worker extends Person{
private String wno;
private String salary;
public String getWno(){
return wno;
}
public void setWno(String wno){
this.wno = wno;
}
public String getSalary(){
return salary;
}
public void setSalary(String salary){
this.salary = salary;
}
}
父类映射文件tb_persons.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!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.hiberbate.manytomany">
<class name="Person" table="tb_persons" abstract="true"><!-- 多设置一个属性abstract="true",因为根本就没有tb_persons表 -->
<id name="id" column="id" type="int" >
<!-- 父类的主键生成策略为‘分配’ -->
<generator class="assigned" />
</id>
<property name="name" type="string">
<column name="name"/>
</property>
<property name="sex" type="string" column="sex"></property>
<property name="age" type="int" column="age"></property>
<!--student具体类-->
<union-subclass name="Student" table="tb_student">
<property column="sno" name="sno" type="string"></property> <!-- 特征属性 -->
<property column="school" name="school" type="string"></property> <!-- 特征属性 -->
</union-subclass>
<!--worker具体类-->
<union-subclass name="Worker" table="tb_worker">
<property column="wno" name="wno" type="string"></property> <!-- 特征属性 -->
<property column="salary" name="salary" type="string"></property> <!-- 特征属性 -->
</union-subclass>
</class>
</hibernate-mapping>
<union-subclass>标签是用于指示出该hbm文件所表示的类的子类,如Person类有两个子 类,就需要两个<union-subclass>标签以此类推。
<union-subclass>标签的"name"属性用于指 定子类的全限定名称,"table"属性用于指定该子类对应的表的名称,"extends"属性用于指定该子类的父类,
注意:"extends"属性与<union-subclass>标签的位置有关,若<union-subclass>标签作为<class>标签的子标签,则"extends"属性可以不设置,否则需要明确设置"extends"属性。
<class>标签中的"abstract"属性如果值为true则,不会生成表结构。如果值为false则会生成表结构,但是不会插入数据。
测试代码:
HibernateUtil类在我的这篇博客《eclipse集成Hibernate5开发过程,配置问题,走过的坑,详细介绍》上面有,就不贴代码了
private static void joinsubclassforsave() {
Session session = null;
//新建学生对象
Student stu = new Student();
stu.setId(9);
stu.setName("张三");
stu.setAge(new Integer(22));
stu.setSex("男");
stu.setSno("100120122016");
stu.setSchool("华中科技大学");
//新建工人对象
Worker worker=new Worker();
worker.setId(101);
worker.setName("李四");
worker.setAge(26);
worker.setSex("男");
worker.setWno("W20121224");
worker.setSalary("8000");
try {
session = HibernateUtil.getSession();
//添加数据
session.beginTransaction();
session.save(stu);
session.save(worker);
session.getTransaction().commit();
} catch (Exception e) {
session.getTransaction().rollback();
System.out.print("数据库添加失败");
e.printStackTrace();
}finally{
HibernateUtil.closeSession();
}
}
注意:上面标红部分,如果id设置成一样,会有如下错误
ERROR StatusLogger Log4j2 could not find a logging implementation. Please add log4j-core to the classpath. Using SimpleLogger to log to the console...
Tue Mar 06 15:24:28 CST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
数据库添加失败org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [com.hiberbate.manytomany.Worker#9]
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:169)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:192)
at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:38)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:177)
at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:32)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:682)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:674)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:669)
at com.book.web3.HibernateTest.joinsubclassforsave(HibernateTest.java:107)
at com.book.web3.HibernateTest.main(HibernateTest.java:44)
这是由于在配置文件中 <union-subclass>
标签中不需要key值了,而且Person的主键生成策略不能是自增(native)了,如果自增的话,Student表中第一条记录id为1,Worker表中第一条记录也为1,而它们在实际意义上属于同一类型(可以看做在一张表中),否则可能造成不同子类对应表中的主键相同,所以主键不可一致。
结果如图: